From: blitz-research Date: Wed, 22 Jan 2014 22:34:04 +0000 (+1300) Subject: Added src. X-Git-Tag: v150~24 X-Git-Url: https://jcornell.net/gitweb/gitweb.cgi?a=commitdiff_plain;h=71686155e3f721fad2d054843b179d1ecfc8fed4;p=blitzmax.git Added src. --- diff --git a/src/bmk/bmk.bmx b/src/bmk/bmk.bmx new file mode 100644 index 0000000..e0ab2e8 --- /dev/null +++ b/src/bmk/bmk.bmx @@ -0,0 +1,317 @@ +' +' Change History : +' BaH 28/09/2007 - Added custom appstub compiles using -b parameter. +' Synched with current bmk source. +' +Strict + +Framework brl.basic + +Import "bmk_make.bmx" +Import "bmk_zap.bmx" +Import "bmk_bb2bmx.bmx" + +?MacOS +Incbin "macos.icns" +? + +If AppArgs.length<2 CmdError + +Local cmd$=AppArgs[1],args$[] + +args=ParseConfigArgs( AppArgs[2..] ) + +CreateDir BlitzMaxPath()+"/tmp" + +Select cmd.ToLower() +Case "makeapp" + SetConfigMung + MakeApplication args,False +Case "makelib" + SetConfigMung + MakeApplication args,True +Case "makemods" +' Local ms=MilliSecs() + If opt_debug Or opt_release + SetConfigMung + MakeModules args + Else + opt_debug=True + opt_release=False + SetConfigMung + MakeModules args + opt_debug=False + opt_release=True + SetConfigMung + MakeModules args + EndIf +' ms=MilliSecs()-ms +' Print "ms="+ms +Case "cleanmods" + CleanModules args +Case "zapmod" + ZapModule args +Case "unzapmod" + UnzapModule args +Case "listmods" + ListModules args +Case "modstatus" + ModuleStatus args +Case "syncmods" + SyncModules args +Case "convertbb" + ConvertBB args +Case "ranlibdir" + RanlibDir args +Default + CmdError +End Select + +Function SetConfigMung() + If opt_release + opt_debug=False + opt_configmung="release" + If opt_threaded opt_configmung:+".mt" + opt_configmung="."+opt_configmung+"."+cfg_platform+"."+opt_arch + Else + opt_debug=True + opt_release=False + opt_configmung="debug" + If opt_threaded opt_configmung:+".mt" + opt_configmung="."+opt_configmung+"."+cfg_platform+"."+opt_arch + EndIf +End Function + +Function SetModfilter( t$ ) + + opt_modfilter=t.ToLower() + + If opt_modfilter="*" + opt_modfilter="" + Else If opt_modfilter[opt_modfilter.length-1]<>"." + opt_modfilter:+"." + EndIf + +End Function + +Function MakeModules( args$[] ) + + If args.length>1 CmdError + + If args.length SetModfilter args[0] Else opt_modfilter="" + + Local mods:TList=EnumModules() + + BeginMake + + MakeMod "brl.blitz" + + For Local name$=EachIn mods + MakeMod name + Next + +End Function + +Function CleanModules( args$[] ) + + If args.length>1 CmdError + + If args.length SetModfilter args[0] Else opt_modfilter="" + + Local mods:TList=EnumModules() + + Local name$ + For name=EachIn mods + + If (name+".").Find(opt_modfilter)<>0 Continue + + Print "Cleaning:"+name + + Local path$=ModulePath(name) + + DeleteDir path+"/.bmx",True + + If Not opt_kill Continue + + For Local f$=EachIn LoadDir( path ) + + Local p$=path+"/"+f + Select FileType(p) + Case FILETYPE_DIR + If f<>"doc" + DeleteDir p,True + EndIf + Case FILETYPE_FILE + Select ExtractExt(f).tolower() + Case "i","a","txt","htm","html" + 'nop + Default + DeleteFile p + End Select + End Select + + Next + Next + +End Function + +Function MakeApplication( args$[],makelib ) + If opt_execute + If Len(args)=0 CmdError + Else + If Len(args)<>1 CmdError + EndIf + + Local Main$=RealPath( args[0] ) + + Select ExtractExt(Main).ToLower() + Case "" + Main:+".bmx" + Case "c","cpp","cxx","mm","bmx" + Default + Throw "Unrecognized app source file type:"+ExtractExt(Main) + End Select + + If FileType(Main)<>FILETYPE_FILE Throw "Unable to open source file '"+Main+"'" + + If Not opt_outfile opt_outfile=StripExt( Main ) + +?Win32 + If makelib + If ExtractExt(opt_outfile).ToLower()<>"dll" opt_outfile:+".dll" + Else + If ExtractExt(opt_outfile).ToLower()<>"exe" opt_outfile:+".exe" + EndIf +? + +?MacOS + If opt_apptype="gui" + + Local appId$=StripDir( opt_outfile ) + + Local exeDir$=opt_outfile+".app",d$,t:TStream + + d=exeDir+"/Contents/MacOS" + Select FileType( d ) + Case FILETYPE_NONE + CreateDir d,True + If FileType( d )<>FILETYPE_DIR + Throw "Unable to create application directory" + EndIf + Case FILETYPE_FILE + Throw "Unable to create application directory" + Case FILETYPE_DIR + End Select + + d=exeDir+"/Contents/Resources" + Select FileType( d ) + Case FILETYPE_NONE + CreateDir d + If FileType( d )<>FILETYPE_DIR + Throw "Unable to create resources directory" + EndIf + Case FILETYPE_FILE + Throw "Unable to create resources directory" + Case FILETYPE_DIR + End Select + + t=WriteStream( exeDir+"/Contents/Info.plist" ) + If Not t Throw "Unable to create Info.plist" + t.WriteLine "" + t.WriteLine "" + t.WriteLine "" + t.WriteLine "" + t.WriteLine "~tCFBundleExecutable" + t.WriteLine "~t"+appId+"" + t.WriteLine "~tCFBundleIconFile" + t.WriteLine "~t"+appId+"" + t.WriteLine "~tCFBundlePackageType" + t.WriteLine "~tAPPL" + t.WriteLine "" + t.WriteLine "" + t.Close + + t=WriteStream( exeDir+"/Contents/Resources/"+appId+".icns" ) + If Not t Throw "Unable to create icons" + Local in:TStream=ReadStream( "incbin::macos.icns" ) + CopyStream in,t + in.Close + t.Close + + opt_outfile=exeDir+"/Contents/MacOS/"+appId + + EndIf +? + BeginMake + + MakeApp Main,makelib + + If opt_execute + + Print "Executing:"+StripDir( opt_outfile ) + + Local cmd$=CQuote( opt_outfile ) + For Local i=1 Until args.length + cmd:+" "+CQuote( args[i] ) + Next + + Sys cmd + + EndIf + +End Function + +Function ZapModule( args$[] ) + If Len(args)<>2 CmdError + + Local modname$=args[0].ToLower() + Local outfile$=RealPath( args[1] ) + + Local stream:TStream=WriteStream( outfile ) + If Not stream Throw "Unable to open output file" + + ZapMod modname,stream + + stream.Close +End Function + +Function UnzapModule( args$[] ) + If Len(args)<>1 CmdError + + Local infile$=args[0] + + Local stream:TStream=ReadStream( infile ) + If Not stream Throw "Unable to open input file" + + UnzapMod stream + + stream.Close +End Function + +Function ListModules( args$[],modid$="" ) + If Len(args)<>0 CmdError + + Throw "Todo!" + +End Function + +Function ModuleStatus( args$[] ) + If Len(args)<>1 CmdError + + ListModules Null,args[0] + +End Function + +Function SyncModules( args$[] ) + If args.length CmdError + + If Sys( BlitzMaxPath()+"/bin/syncmods" ) Throw "SyncMods error" + +End Function + +Function RanlibDir( args$[] ) + If args.length<>1 CmdError + + Ranlib args[0] + +End Function diff --git a/src/bmk/bmk_bank.bmx b/src/bmk/bmk_bank.bmx new file mode 100644 index 0000000..917b66e --- /dev/null +++ b/src/bmk/bmk_bank.bmx @@ -0,0 +1,122 @@ + +Strict + +Import "bmk_config.bmx" + +Import Pub.ZLib + +Function CompressBank:TBank( bank:TBank ) + + Local size=bank.Size() + Local out_size=size+size/10+32 + Local out:TBank=TBank.Create( out_size ) + compress out.Buf()+4,out_size,bank.Buf(),size + out.PokeByte 0,size + out.PokeByte 1,size Shr 8 + out.PokeByte 2,size Shr 16 + out.PokeByte 3,size Shr 24 + out.Resize out_size+4 + Return out + +End Function + +Function UncompressBank:TBank( bank:TBank ) + + Local out_size + out_size:|bank.PeekByte(0) + out_size:|bank.PeekByte(1) Shl 8 + out_size:|bank.PeekByte(2) Shl 16 + out_size:|bank.PeekByte(3) Shl 24 + Local out:TBank=TBank.Create( out_size ) + uncompress out.Buf(),out_size,bank.Buf()+4,bank.Size()-4 + Return out + +End Function + +Function SplitUrl( url$,server$ Var,file$ Var ) + Local i=url.Find( "/",0 ) + If i<>-1 + server=url[..i] + file=url[i..] + Else + server=url + file="/" + EndIf +End Function + +Function HTTPGetBank:TBank( url$ ) + + Local server$,file$ + SplitUrl url,server,file + + Local t_server$=server + If opt_proxy t_server=opt_proxy + + Local t_port=80 + If opt_proxyport t_port=opt_proxyport + + Local stream:TStream=TSocketStream.CreateClient( t_server,t_port ) + If Not stream Return + + stream.WriteLine "GET http://"+url+" HTTP/1.0" + stream.WriteLine "Host: "+server + stream.WriteLine "" + + While Not stream.Eof() + Local t$=stream.ReadLine() + If Not t Exit + Wend + + Local bank:TBank=TBank.Create(0) + Local bank_stream:TStream=TBankStream.Create( bank ) + + CopyStream stream,bank_stream + + bank_stream.Close + stream.Close + + Return bank + +End Function + +Function HTTPPostBank$( bank:TBank,url$ ) + + Local server$,file$ + SplitUrl url,server,file + + Local t_server$=server + If opt_proxy t_server=opt_proxy + + Local t_port=80 + If opt_proxyport t_port=opt_proxyport + + Local stream:TStream=TSocketStream.CreateClient( t_server,t_port ) + If Not stream Return + + stream.WriteLine "POST http://"+url+" HTTP/1.0" + stream.WriteLine "Host: "+server + stream.WriteLine "Content-Type: application/octet-stream" + stream.WriteLine "Content-Length: "+bank.Size() + stream.WriteLine "" + + Local bank_stream:TStream=TBankStream.Create( bank ) + CopyStream bank_stream,stream + bank_stream.Close + + While Not stream.Eof() + Local t$=stream.ReadLine() + If Not t Exit + Wend + + Local r$ + While Not stream.Eof() + Local t$=stream.ReadLine() + r:+t+"~n" + Wend + + stream.Close + + Return r + +End Function + diff --git a/src/bmk/bmk_bb2bmx.bmx b/src/bmk/bmk_bb2bmx.bmx new file mode 100644 index 0000000..daf57ff --- /dev/null +++ b/src/bmk/bmk_bb2bmx.bmx @@ -0,0 +1,758 @@ + +Strict + +' bmk_bb2bmx.bmx v0.4 +' by simonarmstrong@blitzbasic.com + +' converts BlitzBasic source files to BlitzMax + +' history + +' AND OR operators -> bitwise if not followed by conditional operators =<> +' Min and Max -> _Min and _Max +' HandleFromObject and HandleToObject added to bbtype.bmx +' link and list fields in bbtype -> _link and _list +' IncrementArrays$(code$) adds 1 to all array dimensions of array declarations +' ReadString(TStream) function added and FreeSound(sound)->Release(sound) +' hidepointer -> hidemouse showpointer -> showmouse +' delete obj -> obj.remove +' readpixel->dev.blitz3d.readpixel writepixel->dev.blitz3d.writepixel +' seekfile -> seekstream filepos -> streampos +' channelvolume->SetChannelVolume soundvolume-> +' readbytes -> ReadBank writebytes-> WriteBankq +' xor->~ getkey->waitkey mousewait->waitmouse +' handle -> HandleFromObject object -> HandleToObject +' stop -> DebugStop +' .label -> #label +' param[n]->param[] in function declarations +' added TypePrefix$ to help avoid type name / variable name clashes +' processes include files +' output bbtype.bmx and bbvkey.bmx files (thanks to Terabit) +' moved to bmk_bb2bmx +' inline comments replace ; with ' +' command separators replace : with ; +' type specifiers replace . with : +' field separators replace \ with . +' boolean operators replace and or with & | +' array declarations replace Dim x(100) with Global x[100+1] +' graphics commands Line,Rect,Oval,Text -> DrawLine,DrawRect,DrawOval,DrawText +' implement old style Type handling for Each First Last Before After Insert +' Str becomes String +' Delete Each list -> list.Clear() +' Delete -> Release +' Data->DefData Read->ReadData +' KeyDown->VKeyDown KeyHit->VKeyHit +' native Color and ClsColor commands added to header + +' not supported / stubbed out + +' no float->boolean so error is "bitwise operators can only be used with integers" +' MouseZSpeed(), FreeBank(bank), Locate( x,y ) +' LoopSound(sound), ChannelPitch(channel,hz),PlayCDTrack( track,mode=0 ) + +Import brl.retro + +Const TAB$=Chr(9) + +Global TypePrefix$="bb" + +Function main() + Local AppArgs$[]=["bb2bmx","bob.bb"] + Local srcfile$,destfile$ + Local n=Len AppArgs + If n<2 + Print "bb2bmx srcfile.bb [destfile.bmx]" + End + EndIf + srcfile$=AppArgs[1] + destfile$=Replace$(srcfile,".bb",".bmx") + If n>2 destfile$=AppArgs[2] + bb2bmx(srcfile,destfile) +End Function + +Function ConvertBB(args$[]) + Local srcfile$,destfile$ + If Len args<1 Throw "convertbb option requires a filename" + srcfile$=args[0] + If Len args>1 destfile=args[1] + bb2bmx srcfile,destfile +End Function + +Global Includes:TList +Global Complete:TList +Global TypeLists:TList + +Function bb2bmx(srcfile$,destfile$) + Local s$,currdir$,inc$,done$ + Local destinclude$ + Local src:TList,isrc:TList + Local dest:TList,idest:TList + Local incs:TList + + Includes=New TList + TypeLists=New TList + Complete=New TList + + currdir=CurrentDir() + + src=ReadTextFile(srcfile) + If Not src Throw "bb2bmx failed to open "+srcfile + + If Not destfile destfile$=Replace$(srcfile,".bb",".bmx") + ChangeDir ExtractDir(srcfile) + + WriteVKeyFile + WriteBBTypeFile + + dest=New TList + + Print "converting "+srcfile + ConvertSourceList(src,dest) + +' process includes + + While Not Includes.IsEmpty() + incs=Includes + Includes=New TList + For srcfile=EachIn incs + +' check if include already converted + + For done=EachIn complete + If done=srcfile Exit + Next + If done=srcfile Continue + + complete.AddLast srcfile + isrc=ReadTextFile(srcfile) + If Not isrc Throw "bb2bmx failed to open included file "+srcfile + ChangeDir ExtractDir(srcfile) + + idest=New TList + Print "converting "+srcfile + + ConvertSourceList(isrc,idest) + destinclude$=Replace$(srcfile,".bb",".bmx") + WriteTextFile(destinclude,idest) + Next + Wend + + ChangeDir(currdir) + + For s$=EachIn TypeLists + dest.addfirst s$ + Next + + dest.addfirst "" + dest.addfirst "Import "+Chr(34)+"bbvkey.bmx"+Chr(34) + dest.addfirst "Import "+Chr(34)+"bbtype.bmx"+Chr(34) + + WriteTextFile(destfile,dest) + +End Function + +Function ProcessInclude$(s$) + Local path$,inc$ + Local q,r + + q=Instr(s,Chr(34)) + If q=0 Return s$ + r=Instr(s,Chr(34),q+1) + If r=0 Return s$ + path$=s[q..r-1] + + path=RealPath(path$) + For inc=EachIn Includes + If inc=path Exit + Next + If inc<>path + Includes.AddLast(path) + EndIf + + Return Replace$(s$,".bb",".bmx") +End Function + +Function FindToken(s$,t$,p) + Local l$,c + t=Lower(t) + l=Lower(s) + Repeat + p=Instr(l,t,p+1) + If Not p Exit + If p>1 + c=l[p-2] + If c>47 And c<58 Continue '0-9 + If c>95 And c<122 Continue 'a-z + If c=Asc("_") Continue + EndIf + If p+Len(t)-147 And c<58 Continue '0-9 + If c>95 And c<122 Continue 'a-z + If c=Asc("_") Continue + EndIf + Return p + Forever +End Function + +Function ReplaceToken$(s$,t$,r$) + Local l$,p,c + Repeat + p=FindToken(s,t,p) + If Not p Exit + s=s[..p-1]+r$+s[p+Len(t)-1..] + p:+Len r$ + Forever + Return s +End Function + +Function FindEOC(s$,p) 'return position of next space or command separator + Local q,r + q=Instr(s," ",p) + If q=0 q=Len s+1 + r=Instr(s,";",p) + If r And r",p) + If r And r = convert to bool operator & | + Local p,q,r,t + + While True + t=FindToken(s$,"And",p) + If t=0 Exit + q=Len(s$) + r=FindToken(s$,"Then",t) + If r And r",t);If r And r<=q p=q;Continue + s$=s[..t-1]+"&"+s[t+2..] + Wend + p=0 + While True + t=FindToken(s$,"Or",p) + If t=0 Exit + q=Len(s$) + r=FindToken(s$,"Then",t) + If r And r",t);If r And r<=q p=q;Continue + s$=s[..t-1]+"|"+s[t+1..] + Wend + Return s$ +End Function + +Function Convert$(s$) 'substring of source line before rem and between any string literals + Local p,q,r,c,n$ +' replace : command separator + s$=Replace(s$,":",";") +'.label->#label + p=Instr(Trim(s),".") + If p=1 + p=Instr(s,".") + s="#"+s[p..] + EndIf +' replace . type specifier + p=1 + Repeat + p=Instr(s,".",p+1) + If Not p Exit + c=s[p] + If c>47 And c<58 Continue 'ignore if decimal point + s=s[..p-1]+":"+TypePrefix$+s[p..] + Forever +' replace \ field separator + s$=Replace(s$,"\",".") +' update BASIC API name changes + s$=ReplaceToken(s,"freesound","Release") + s$=ReplaceToken(s,"channelpan","SetChannelPan") + s$=ReplaceToken(s,"filepos","StreamPos") + s$=ReplaceToken(s,"seekfile","SeekStream") + s$=ReplaceToken(s,"channelvolume","SetChannelVolume") + s$=ReplaceToken(s,"readbytes","ReadBank") + s$=ReplaceToken(s,"writebytes","WriteBank") + s$=ReplaceToken(s,"mousewait","WaitMouse") +' hidepointer -> hidemouse showpointer -> showmouse + s$=ReplaceToken(s,"hidepointer","HideMouse") + s$=ReplaceToken(s,"showpointer","ShowMouse") +' replace boolean operators + s$=ReplaceToken(s,"xor","~~") + s$=ReplaceToken(s,"stop","DebugStop") + +Rem + s$=ReplaceToken(s,"and","&") + s$=ReplaceToken(s,"or","|") + s$=ReplaceToken(s,"chr$","chr") + + s$=ReplaceToken(s,"line","DrawLine") + s$=ReplaceToken(s,"rect","DrawRect") + s$=ReplaceToken(s,"oval","DrawOval") + s$=ReplaceToken(s,"text","DrawText") + s$=ReplaceToken(s,"color","SetColor") + s$=ReplaceToken(s,"clscolor","SetCLSColor") +EndRem + s$=ReplaceToken(s,"str","String") + s$=ReplaceToken(s,"read","ReadData") + s$=ReplaceToken(s,"data","DefData") + s$=ReplaceToken(s,"restore","RestoreData") + s$=ReplaceToken(s,"keydown","VKeyDown") + s$=ReplaceToken(s,"keyhit","VKeyHit") + s$=ReplaceToken(s,"getkey","WaitKey") + s$=ReplaceToken(s,"readpixel","dev.blitz3d.ReadPixel") 'ReadPixelBuffer") + s$=ReplaceToken(s,"writepixel","dev.blitz3d.WritePixel") + s$=ReplaceToken(s,"graphicswidth","dev.blitz3d.GraphicsWidth") + s$=ReplaceToken(s,"graphicsheight","dev.blitz3d.GraphicsHeight") + + s$=ReplaceToken(s,"min","fmin") + s$=ReplaceToken(s,"max","fmax") + +' delete obj -> obj.remove + p=0 + Repeat + p=FindToken(s,"delete",p) + If Not p Exit + If Lower(s[p+5..p+10])=" each" s=s[..p+5]+"Each "+TypePrefix$+Trim(s[p+10]);Continue + If Lower(s[p+5..p+11])=" first" s=s[..p+5]+"First "+TypePrefix$+Trim(s[p+11]);Continue + If Lower(s[p+5..p+10])=" last" s=s[..p+5]+"Last "+TypePrefix$+Trim(s[p+10]);Continue + q=Instr(s," ",p+7) + If q=0 q=Len s+1 + r=Instr(s,";",p+7) + If r And r HandleFromObject(obj) object.blah(handle) -> HandleToObject(handle) + + s$=ReplaceToken(s,"handle","HandleFromObject") + p=0 + Repeat + p=FindToken(s,"object",p) + If p=0 Exit + q=Instr(s,":",p) + If q=0 Exit + r=Instr(s,"(",q) + If r=0 Exit + n$=s[q..r-1] + c=1 + q=r + While c + If r>Len(s) Exit + If s[r]="(" c:+1 + If s[r]=")" c:-1 + r:+1 + Wend + s=s[..p-1]+n$+"(HandleToObject"+s[q-1..r-1]+")"+s[r..] + p=p+Len(n)+16 + Forever + +' replace New Type with New prefix_type + p=0 + Repeat + p=FindToken(s,"New",p) + If Not p Exit + s=s[..p+3]+TypePrefix$+s[p+3..] + p=p+1 + Forever +' replace Dim var(size) with Global var[size] + p=0 + Repeat + p=FindToken(s,"Dim",p) + If Not p Exit + s=s[..p-1]+"Global"+s[p+2..] + Repeat + p=Instr(s,"(",p) + If Not p Exit + s=s[..p-1]+"["+s[p..] + p=Instr(s,")",p) + If Not p Exit + s=s[..p-1]+"]"+s[p..] 'was +1 + Forever + s=IncrementArrays(s$) + Exit 'no multiple dim calls pre +' if not p exit + Forever +' replace function(param[4]) with function(param[]) + p=0 + Repeat + p=FindToken(s,"Function",p) + If Not p Exit + p=Instr(s,"(",p) + If Not p Exit + q=Instr(s,")",p) + If Not q Exit + n$=StripDims(s[p..q-1]) + s=s[..p]+n+s[q-1..] + Exit + Forever +' for b=each bob -> for b=eachin bob.list + p=0 + Repeat + p=FindToken(s,"Each",p) + If Not p Exit + q=FindEOC(s,p+6) + s=s[..p-1]+"EachIn "+Trim(s[p+4..q-1])+"_list"+s[q-1..] + p=q + Forever +' First class + p=0 + Repeat + p=FindToken(s,"First",p) + If Not p Exit + q=FindEOC(s,p+7) + n$=Trim(s[p+5..q-1]) + s=s[..p-1]+TypePrefix+n+"("+n+"_list.First())"+s[q-1..] + p=q+Len(n)*2+14 + Forever +' Last class + p=0 + Repeat + p=FindToken(s,"Last",p) + If Not p Exit + q=FindEOC(s,p+6) + n$=Trim(s[p+4..q-1]) + s=s[..p-1]+TypePrefix+n+"("+n+"_list.Last())"+s[q-1..] + p=q+Len(n)*2+13 + Forever +' Insert b Before|After bob -> b.InsertAfter(bob) + p=0 + Repeat + p=FindToken(s,"Insert",p) + If Not p Exit + q=Instr(s," ",p+7) + If Not q Exit + n$=Lower(s[q..]) + If n$[..6]="before" + n$="Before" + r=q+7 + ElseIf n$[..5]="after" + n$="After" + r=q+6 + Else + Exit + EndIf + c=FindEOC(s,r+1) + s=s[..p-1]+s[p+6..q-1]+".Insert"+n$+"("+s[r..c-1]+")"+s[c..] 'n$+ simon was here + p=c + Forever +' After b -> b.After() + p=0 + Repeat + p=FindToken(s,"After",p) + If Not p Exit + q=Instr(s," ",p+7) + If q=0 q=Len s+1 + r=Instr(s,";",p+7) + If r And r b.Before() + p=0 + Repeat + p=FindToken(s,"Before",p) + If Not p Exit + q=Instr(s," ",p+8) + If q=0 q=Len s+1 + r=Instr(s,";",p+8) + If r And r1 p=Instr(l$,"end rem") + If p=1 + inrem=0 + EndIf + Else +' parse strings and remarks + out$="" + in$=fixquotes(in$) + While in$ + q=Instr(in$,Chr(34)) + r=Instr(in$,";") + inrem=Instr(l$,"rem ") + If inrem And inrem Include "blah.bmx" + + If l$[..8]="include " Or l$[..8]="include"+Chr$(34) + out=ProcessInclude(out) + EndIf + + dest.AddLast out + + Next +End Function + +Function ReadTextFile:TList(file$) + Local f:TStream,n + Local txt:TList + txt=New TList + f=ReadStream(file) + If Not f Return Null + While Not Eof(f) + txt.AddLast ReadLine(f) + n:+1 + Wend + Return txt +End Function + +Function WriteTextFile(file$,txt:TList) + Local f:TStream,l$ + f=WriteStream(file) + If Not f Return + For l$=EachIn txt + WriteLine f,l + Next + CloseStream f +End Function + +Function WriteVKeyFile() + Local dest:TStream=WriteFile("bbvkey.bmx") + If Not dest Return + WriteLine dest,"' virtual key support for legacy Blitz apps" + WriteLine dest,"" + WriteLine dest,"Global VKEY[]=[.." + WriteLine dest,"0,KEY_ESCAPE,KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,KEY_8,KEY_9,KEY_0,.." + WriteLine dest,"KEY_MINUS,KEY_EQUALS,KEY_BACKSPACE,KEY_TAB,KEY_Q,KEY_W,KEY_E,KEY_R,KEY_T,.." + WriteLine dest,"KEY_Y,KEY_U,KEY_I,KEY_O,KEY_P,KEY_OPENBRACKET,KEY_CLOSEBRACKET,KEY_RETURN,.." + WriteLine dest,"KEY_LCONTROL,KEY_A,KEY_S,KEY_D,KEY_F,KEY_G,KEY_H,KEY_J,KEY_K,KEY_L,.." + WriteLine dest,"KEY_SEMICOLON,KEY_QUOTES,KEY_TILDE,KEY_LSHIFT,KEY_BACKSLASH,.." + WriteLine dest,"KEY_Z,KEY_X,KEY_C,KEY_V,KEY_B,KEY_N,KEY_M,KEY_COMMA,KEY_PERIOD,KEY_SLASH,.." + WriteLine dest,"KEY_RSHIFT,KEY_NUMMULTIPLY,KEY_ALT,KEY_SPACE,KEY_CAPSLOCK,.." + WriteLine dest,"KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,.." + WriteLine dest,"KEY_NUMLOCK,KEY_SCROLL,KEY_NUM7,KEY_NUM8,KEY_NUM9,KEY_NUMSUBTRACT,KEY_NUM4,.." + WriteLine dest,"KEY_NUM5,KEY_NUM6,KEY_NUMADD,KEY_NUM1,KEY_NUM2,KEY_NUM3,KEY_NUM0,.." + WriteLine dest,"KEY_NUMDECIMAL,KEY_NUMSLASH,KEY_F11,KEY_F12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,.." + WriteLine dest,"0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,.." + WriteLine dest,"KEY_EQUALS,0,0,KEY_MEDIA_PREV_TRACK,0,0,0,0,0,0,0,0,KEY_MEDIA_NEXT_TRACK,0,0,.." + WriteLine dest,"KEY_ENTER,KEY_RCONTROL,0,0,KEY_VOLUME_MUTE,0,KEY_MEDIA_PLAY_PAUSE,0,.." + WriteLine dest,"KEY_MEDIA_STOP,0,0,0,0,0,0,0,0,0,KEY_VOLUME_DOWN,0,KEY_VOLUME_UP,0,.." + WriteLine dest,"KEY_BROWSER_HOME,KEY_DECIMAL,0,KEY_NUMDIVIDE,0,KEY_SCREEN,.." + WriteLine dest,"0,0,0,0,0,0,0,0,0,0,0,0,0,KEY_PAUSE,0,KEY_HOME,KEY_UP,KEY_PAGEUP,0,.." + WriteLine dest,"KEY_LEFT,0,KEY_RIGHT,0,KEY_END,KEY_DOWN,KEY_PAGEDOWN,KEY_INSERT,KEY_DELETE,.." + WriteLine dest,"0,0,0,0,0,0,0,KEY_LWIN,KEY_RWIN,0,0,0,0,0,0,0,0,KEY_BROWSER_SEARCH,.." + WriteLine dest,"KEY_BROWSER_FAVORITES,KEY_BROWSER_REFRESH,KEY_BROWSER_STOP,KEY_BROWSER_FORWARD,.." + WriteLine dest,"KEY_BROWSER_BACK,0,KEY_LAUNCH_MAIL,KEY_LAUNCH_MEDIA_SELECT]" + WriteLine dest,"" + WriteLine dest,"Function VKeyDown(key);return KeyDown(VKEY[key]);End Function" + WriteLine dest,"Function VKeyHit(key);return KeyHit(VKEY[key]);End Function" + WriteLine dest,"" + WriteLine dest,"'currently unsupported in BlitzMax" + WriteLine dest,"" + WriteLine dest,"Function Locate( x,y );return 0;End Function" + WriteLine dest,"Function MouseZSpeed();return 0;End Function" + WriteLine dest,"Function FreeBank(bank);return 0;End Function" + WriteLine dest,"Function LoopSound(sound);return 0;End Function" + WriteLine dest,"Function ChannelPitch(channel,hz);return 0;End Function" + WriteLine dest,"Function PlayCDTrack( track,mode=0 );return 0;End Function" + WriteLine dest,"Function SoundVolume( sound,volume# );return 0;End Function" + WriteLine dest,"" + CloseFile dest +End Function + +Function WriteBBTypeFile() + Local dest:TStream=WriteFile("bbtype.bmx") + If Not dest Return + WriteLine dest,"' BBType adds legacy Type functionality to BlitzMax Type" + WriteLine dest,"" + WriteLine dest,"Type TBBType" + WriteLine dest,"" + WriteLine dest," Field _list:TList" + WriteLine dest," Field _link:TLink" + WriteLine dest,"" + WriteLine dest," Method Add(t:TList)" + WriteLine dest," _list=t" + WriteLine dest," _link=_list.AddLast(self)" + WriteLine dest," End Method" + WriteLine dest,"" + WriteLine dest," Method InsertBefore(t:TBBType)" + WriteLine dest," _link.Remove" + WriteLine dest," _link=_list.InsertBeforeLink(self,t._link)" + WriteLine dest," End Method" + WriteLine dest,"" + WriteLine dest," Method InsertAfter(t:TBBType)" + WriteLine dest," _link.Remove" + WriteLine dest," _link=_list.InsertAfterLink(self,t._link)" + WriteLine dest," End Method" + WriteLine dest,"" + WriteLine dest," Method Remove()" + WriteLine dest," _list.remove self" + WriteLine dest," End Method" + WriteLine dest,"" + WriteLine dest,"End Type" + WriteLine dest,"" + WriteLine dest,"Function DeleteLast(t:TBBType)" + WriteLine dest," if t TBBType(t._list.Last()).Remove()" + WriteLine dest,"End Function" + WriteLine dest,"" + WriteLine dest,"Function DeleteFirst(t:TBBType)" + WriteLine dest," if t TBBType(t._list.First()).Remove()" + WriteLine dest,"End Function" + WriteLine dest,"" + WriteLine dest,"Function DeleteEach(t:TBBType)" + WriteLine dest," if t t._list.Clear()" + WriteLine dest,"End Function" + WriteLine dest,"" + WriteLine dest,"Function ReadString$(in:TStream)" + WriteLine dest," local length" + WriteLine dest," length=readint(in)" + WriteLine dest," if length>0 and length<1024*1024 return brl.stream.readstring(in,length)" + WriteLine dest,"End Function" + WriteLine dest,"" + WriteLine dest,"Function HandleToObject:Object(obj:Object)" + WriteLine dest," Return obj" + WriteLine dest,"End Function" + WriteLine dest,"" + WriteLine dest,"Function HandleFromObject(obj:Object)" + WriteLine dest," Local h=HandleToObject(obj)" + WriteLine dest," Return h" + WriteLine dest,"End Function" + WriteLine dest,"" + WriteLine dest,"" + CloseFile dest +End Function diff --git a/src/bmk/bmk_config.bmx b/src/bmk/bmk_config.bmx new file mode 100644 index 0000000..8801f0e --- /dev/null +++ b/src/bmk/bmk_config.bmx @@ -0,0 +1,159 @@ + +Strict + +Import BRL.MaxUtil + +Import Pub.MacOS + +Const ALL_SRC_EXTS$="bmx;i;c;m;cpp;cxx;cc;mm;h;hpp;hxx;hh;s;asm" + +Global opt_arch$ +Global opt_server$ +Global opt_outfile$ +Global opt_framework$ +Global opt_apptype$="console" +Global opt_debug=False +Global opt_threaded=False +Global opt_release=False +Global opt_configmung$="" +Global opt_kill=False +Global opt_username$="nobody" +Global opt_password$="anonymous" +Global opt_modfilter$="." +Global opt_all=False +Global opt_quiet=False +Global opt_verbose=False +Global opt_execute=False +Global opt_proxy$ +Global opt_proxyport +Global opt_traceheaders +Global opt_appstub$="brl.appstub" ' BaH 28/9/2007 + +Global opt_dumpbuild + +Global cfg_platform$ + +?MacOS + +cfg_platform="macos" +Global macos_version +Gestalt Asc("s")Shl 24|Asc("y")Shl 16|Asc("s")Shl 8|Asc("v"),macos_version + +?MacOsPPC +If is_pid_native(0) opt_arch="ppc" Else opt_arch="x86" + +?MacOsX86 +If is_pid_native(0) opt_arch="x86" Else opt_arch="ppc" + +?Win32 + +opt_arch="x86" +cfg_platform="win32" + +'Fudge PATH so exec sees our MinGW first! +Local mingw$=getenv_( "MINGW" ) +If mingw + Local path$=getenv_( "PATH" ) + If path + path=mingw+"\bin;"+path + putenv_ "PATH="+path + EndIf +EndIf + +?Linux + +opt_arch="x86" +cfg_platform="linux" + +? + +ChangeDir LaunchDir + +Function CmdError() + Throw "Command line error" +End Function + +Function ParseConfigArgs$[]( args$[] ) + + Local n + + If getenv_( "BMKDUMPBUILD" ) + opt_dumpbuild=1 + opt_quiet=True + EndIf + + For n=0 Until args.length + Local arg$=args[n] + If arg[..1]<>"-" Exit + Select arg[1..] + Case "a" + opt_all=True + Case "q" + opt_quiet=True + Case "v" + opt_verbose=True + Case "x" + opt_execute=True + Case "d" + opt_debug=True + opt_release=False + Case "r" + opt_debug=False + opt_release=True + Case "h" + opt_threaded=True + Case "k" + opt_kill=True + Case "z" + opt_traceheaders=True + Case "y" + n:+1 + If n=args.length CmdError + opt_proxy=args[n] + Local i=opt_proxy.Find(":") + If i<>-1 + opt_proxyport=Int( opt_proxy[i+1..] ) + opt_proxy=opt_proxy[..i] + EndIf + Case "g" + n:+1 + If n=args.length CmdError + opt_arch=args[n].ToLower() + Case "t" + n:+1 + If n=args.length CmdError + opt_apptype=args[n].ToLower() + Case "o" + n:+1 + If n=args.length CmdError + opt_outfile=args[n] + Case "f" + n:+1 + If n=args.length CmdError + opt_framework=args[n] + Case "s" + n:+1 + If n=args.length CmdError + opt_server=args[n] + Case "u" + n:+1 + If n=args.length CmdError + opt_username=args[n] + Case "p" + n:+1 + If n=args.length CmdError + opt_password=args[n] + Case "b" + n:+1 + If n=args.length CmdError + opt_appstub=args[n] + Default + CmdError + End Select + Next + + Return args[n..] + +End Function + + diff --git a/src/bmk/bmk_make.bmx b/src/bmk/bmk_make.bmx new file mode 100644 index 0000000..f6a253c --- /dev/null +++ b/src/bmk/bmk_make.bmx @@ -0,0 +1,395 @@ + +Strict + +Import "bmk_modutil.bmx" + +Rem +Experimental speedup hack by Mark! + +Should allow you to modify non-interface affecting code without triggering lots of recompiles. + +Works by determining whether blah.bmx's .i file physically changes after blah.bmx is compiled. + +If not, then anything importing blah.bmx may not need to be recompiled. + +Uses a new '.i2' file which is updated only when actual .i file content changes. +End Rem +Global EXPERIMENTAL_SPEEDUP + +Local t$=getenv_( "BMK_SPEEDUP" ) +If t EXPERIMENTAL_SPEEDUP=True + +Type TFile + + Field path$,time + + Function Create:TFile( path$,files:TList ) + Local f:TFile=New TFile + f.path=path + f.time=FileTime(path) + If files files.AddFirst f + Return f + End Function + +End Type + +Global cc_opts$ +Global bcc_opts$ +Global app_main$ +Global app_type$ +Global src_files:TList +Global obj_files:TList +Global lnk_files:TList +Global tmp_stack:TList +Global ext_files:TList + +Function Push( o:Object ) + tmp_stack.AddLast o +End Function + +Function Pop:Object() + Return tmp_stack.RemoveLast() +End Function + +Function FindFile:TFile( path$,files:TList ) + path=path.ToLower() + Local f:TFile + For f=EachIn files + If f.path.ToLower()=path Return f + Next +End Function + +Function MaxTime( files:TList ) + Local f:TFile,t + For f=EachIn files + If f.time>t t=f.time + Next + Return t +End Function + +Function FilePaths:TList( files:TList ) + Local f:TFile,p:TList=New TList + For f=EachIn files + p.AddLast f.path + Next + Return p +End Function + +Function AddList( src:TList,dst:TList ) + Local t:Object + For t=EachIn src + dst.AddLast t + Next +End Function + +Function BeginMake() + cc_opts=Null + bcc_opts=Null + app_main=Null + src_files=New TList + obj_files=New TList + lnk_files=New TList + tmp_stack=New TList + ext_files=New TList +End Function + +'returns mod interface file +Function MakeMod:TFile( mod_name$ ) + + Local path$=ModulePath(mod_name) + Local id$=ModuleIdent(mod_name) + Local src_path$=path+"/"+id+".bmx" + Local arc_path$=path+"/"+id+opt_configmung+".a" + Local iface_path$=path+"/"+id+opt_configmung+".i" + + mod_opts = New TModOpt ' BaH + + Local iface:TFile=FindFile( iface_path,src_files ) + If iface Return iface + + Assert Not FindFile( arc_path,lnk_files ) + + Local arc:TFile=TFile.Create( arc_path,Null ) + + If (mod_name+".").Find(opt_modfilter)=0 And FileType(src_path)=FILETYPE_FILE + + Push cc_opts + Push bcc_opts + Push obj_files + + cc_opts="" + cc_opts:+" -I"+CQuote(path) + cc_opts:+" -I"+CQuote(ModulePath("")) + + If opt_release cc_opts:+" -O2 -DNDEBUG" + If opt_threaded cc_opts:+" -DTHREADED" + + bcc_opts=" -g "+opt_arch + bcc_opts:+" -m "+mod_name$ + + If opt_quiet bcc_opts:+" -q" + If opt_verbose bcc_opts:+" -v" + If opt_release bcc_opts:+" -r" + If opt_threaded bcc_opts:+" -h" + + obj_files=New TList + + MakeSrc src_path,True + + If MaxTime( obj_files )>arc.time Or opt_all + If Not opt_quiet Print "Archiving:"+StripDir(arc_path) + CreateArc arc_path,FilePaths( obj_files ) + arc.time=FileTime(arc_path) + EndIf + + obj_files=TList(Pop()) + bcc_opts=String(Pop()) + cc_opts=String(Pop()) + EndIf + + Local src:TFile=MakeSrc( iface_path,False ) + + lnk_files.AddFirst arc + + Return src + +End Function + +'adds to obj_files +'returns input src file +Function MakeSrc:TFile( src_path$,buildit ) + + Local src:TFile=FindFile( src_path,src_files ) + If src Return src + + If FileType( src_path )<>FILETYPE_FILE Return + + src=TFile.Create( src_path,src_files ) + + Local src_file:TSourceFile=ParseSourceFile( src_path ) + If Not src_file Return + + Local main_file=(src_path=app_main) + + Local keep_opts:TModOpt = mod_opts ' BaH + + If main_file + If src_file.framewk + If opt_framework Throw "Framework already specified on commandline" + opt_framework=src_file.framewk + bcc_opts:+" -f "+opt_framework + MakeMod opt_framework + Else + If app_type="bmx" + For Local t$=EachIn EnumModules() + If t.Find("brl.")=0 Or t.Find("pub.")=0 + If t<>"brl.blitz" And t<>opt_appstub MakeMod t + EndIf + Next + EndIf + EndIf + Else If src_file.framewk + Throw "Framework must appear in main source file" + EndIf + + mod_opts = keep_opts ' BaH + + push cc_opts + Push CurrentDir() + + ChangeDir ExtractDir( src_path ) + + Local src_ext$=ExtractExt( src_path ).ToLower() + + If Match( src_ext,"bmx;i" ) + 'incbins + For Local inc$=EachIn src_file.incbins + Local time=FileTime( inc ) + If time>src.time src.time=time + Next + 'includes + For Local inc$=EachIn src_file.includes + Local inc_ext$=ExtractExt(inc).ToLower() + If Match(inc_ext,"bmx") + Local dep:TFile=MakeSrc(RealPath(inc),False) + If Not dep Continue + If dep.time>src.time src.time=dep.time + Else + Throw "Unrecognized Include file type: "+inc + EndIf + Next + + 'module imports + For Local imp$=EachIn src_file.modimports + Local dep:TFile=MakeMod(imp) + If Not dep Continue + cc_opts:+" -I"+CQuote(ExtractDir(dep.path)) + If dep.time>src.time src.time=dep.time + Next + + mod_opts = keep_opts ' BaH + + For Local imp$=EachIn mod_opts.ld_opts ' BaH + ext_files.AddLast TModOpt.setPath(imp, ExtractDir(src_path)) + Next + + 'quoted imports + For Local imp$=EachIn src_file.imports + If imp[0]=Asc("-") + ext_files.AddLast imp + Continue + EndIf + Local imp_ext$=ExtractExt(imp).ToLower() + If Match( imp_ext,"h;hpp;hxx;hh" ) + cc_opts:+" -I"+CQuote(RealPath(ExtractDir(imp))) + Else If Match( imp_ext,"o;a;lib" ) + ext_files.AddLast RealPath(imp) + Else If Match( imp_ext,ALL_SRC_EXTS ) + + Local dep:TFile=MakeSrc(RealPath(imp),True) + + If Not dep Or Not Match( imp_ext,"bmx;i" ) Continue + + If EXPERIMENTAL_SPEEDUP And Match( imp_ext,"bmx" ) + Local p$=ExtractDir( dep.path )+"/.bmx" + Local i_path$=p+"/"+StripDir( dep.path )+opt_configmung+".i2" + If FileType( i_path )=FILETYPE_FILE + Local i_time=FileTime( i_path ) + If i_time>src.time src.time=i_time + Else + If dep.time>src.time src.time=dep.time + EndIf + Else + If dep.time>src.time src.time=dep.time + EndIf + + Else + Throw "Unrecognized Import file type: "+imp + EndIf + Next + Else If Match( src_ext,"c;m;cpp;cxx;cc;mm;h;hpp;hxx;hh" ) + For Local inc$=EachIn src_file.includes + Local inc_ext$=ExtractExt(inc).ToLower() + If Not Match(inc_ext,"h;hpp;hxx;hh") + Continue + EndIf + Local path$=RealPath(inc) + Local dep:TFile=MakeSrc(path,False) + If dep And dep.time>src.time src.time=dep.time + If Not opt_traceheaders Continue + Local src$=StripExt(path)+".cpp" + If FileType(src)<>FILETYPE_FILE + src="" + EndIf + If Not src Continue + MakeSrc src,True + Next + EndIf + + If buildit And Match( src_ext,"bmx;c;m;cpp;cxx;cc;mm;s;asm" ) + + Local p$=ExtractDir( src_path )+"/.bmx" + + If opt_dumpbuild Or FileType( p )=FILETYPE_NONE + CreateDir p + 'Sys "mkdir "+p 'Windows no likey... + EndIf + + If FileType( p )<>FILETYPE_DIR Throw "Unable to create temporary directory" + + Local obj_path$=p+"/"+StripDir( src_path ) + If main_file obj_path:+"."+opt_apptype + obj_path:+opt_configmung+".o" + + If src.time>FileTime( obj_path ) Or opt_all + + If Not opt_quiet Print "Compiling:"+StripDir(src_path) + Select src_ext + Case "bmx" + Local opts$=bcc_opts + If main_file opts=" -t "+opt_apptype+opts + + CompileBMX src_path,obj_path,opts + + If EXPERIMENTAL_SPEEDUP + Local i_path$=StripExt( obj_path )+".i" + + If FileType( i_path )=FILETYPE_FILE + + Local i_path2$=i_path+"2",update=True + + If Not opt_all And FileType( i_path2 )=FILETYPE_FILE And src.time=FileTime( src.path ) + If FileSize( i_path )=FileSize( i_path2 ) + Local i_bytes:Byte[]=LoadByteArray( i_path ) + Local i_bytes2:Byte[]=LoadByteArray( i_path2 ) + If i_bytes.length=i_bytes2.length And memcmp_( i_bytes,i_bytes2,i_bytes.length )=0 + update=False + EndIf + EndIf + EndIf + If update CopyFile i_path,i_path2 + EndIf + EndIf + + Case "c","m","cpp","cxx","cc","mm" + CompileC src_path,obj_path,cc_opts + Case "s","asm" + Assemble src_path,obj_path + End Select + EndIf + Local obj:TFile=TFile.Create( obj_path,obj_files ) + lnk_files.AddFirst obj + EndIf + + ChangeDir String(Pop()) + cc_opts=String(Pop()) + + Return src + +End Function + +Function MakeApp:TFile( Main$,makelib ) + + app_main=Main + + cc_opts="" + cc_opts:+" -I"+CQuote(ModulePath("")) + + If opt_release cc_opts:+" -O2 -DNDEBUG" + If opt_threaded cc_opts:+" -DTHREADED" + + bcc_opts=" -g "+opt_arch + + If opt_quiet bcc_opts:+" -q" + If opt_verbose bcc_opts:+" -v" + If opt_release bcc_opts:+" -r" + If opt_threaded bcc_opts:+" -h" + + If opt_framework bcc_opts:+" -f "+opt_framework + + Local app_ext$=ExtractExt( app_main ).ToLower() + Select app_ext + Case "bmx" + app_type="bmx" + MakeMod "brl.blitz" + MakeSrc Main,True + MakeMod opt_appstub + Case "c","cpp","cxx","cc","mm" + app_type="c/c++" + If opt_framework MakeMod opt_framework + MakeSrc Main,True + Default + Throw "Unrecognized app source file extension:"+app_ext + End Select + + If MaxTime( lnk_files )>FileTime( opt_outfile ) Or opt_all + If Not opt_quiet Print "Linking:"+StripDir( opt_outfile ) + lnk_files=FilePaths( lnk_files ) + AddList ext_files,lnk_files + LinkApp opt_outfile,lnk_files,makelib + EndIf + + app_main="" + +End Function + diff --git a/src/bmk/bmk_modinfo.bmx b/src/bmk/bmk_modinfo.bmx new file mode 100644 index 0000000..7f2c99d --- /dev/null +++ b/src/bmk/bmk_modinfo.bmx @@ -0,0 +1,60 @@ + +Strict + +Import "bmk_modutil.bmx" +Import "bmk_util.bmx" + +Type TInfo + Field info:TList=New TList + + Method Find$( key$ ) + key=key.ToLower()+":" + For Local t$=EachIn info + If t.ToLower()[..Len(key)]=key Return t[Len(key)..].Trim() + Next + End Method + + Method ReadFromStream:TModInfo( stream:TStream ) + While Not stream.Eof() + Local t$=stream.ReadLine() + If Not t Return + info.AddLast t + Wend + End Method +End Type + +Type TModInfo Extends TInfo + + Field name$ + Field version# + Field modprivs$ + Field modserver$ + Field serverinfo:Object + + Function CreateFromModule:TModInfo( name$ ) + Local path$=ModuleInterface( name,"release."+cfg_platform+"."+opt_arch ) + If FileType(path)<>FILETYPE_FILE Return + Local src:TSourceFile=ParseSourceFile( path ) + If Not src Return + Local modinfo:TModInfo=New TModInfo + modinfo.name=name + modinfo.info=src.info + modinfo.info.AddFirst "Module: "+name + modinfo.version=Float( modinfo.Find( "Version" ) ) + modinfo.modserver=modinfo.Find( "ModServer" ) + Return modinfo + End Function + + Function CreateFromStream:TModInfo( stream:TStream ) + Local modinfo:TModInfo=New TModInfo + modinfo.ReadFromStream stream + modinfo.name=modinfo.Find( "Module" ) + If Not modinfo.name Return + modinfo.version=Float( modinfo.Find( "Version" ) ) + modinfo.modprivs=modinfo.Find( "ModPrivs" ) + modinfo.modserver=modinfo.Find( "ModServer" ) + Return modinfo + End Function + +End Type + diff --git a/src/bmk/bmk_modutil.bmx b/src/bmk/bmk_modutil.bmx new file mode 100644 index 0000000..aeab773 --- /dev/null +++ b/src/bmk/bmk_modutil.bmx @@ -0,0 +1,187 @@ + +Strict + +Import BRL.MaxUtil +Import BRL.TextStream + +Import "bmk_util.bmx" + +Type TSourceFile + Field ext$ 'one of: "bmx", "i", "c", "cpp", "m", "s", "h" + Field path$ + Field modid$ + Field framewk$ + Field info:TList=New TList + + Field modimports:TList=New TList + + Field imports:TList=New TList + Field includes:TList=New TList + Field incbins:TList=New TList + + Field declids:TList=New TList +End Type + +Function CharIsDigit( ch ) + Return ch>=Asc("0") And ch<=Asc("9") +End Function + +Function CharIsAlpha( ch ) + Return ch=Asc("_") Or (ch>=Asc("a") And ch<=Asc("z")) Or (ch>=Asc("A") And ch<=Asc("Z")) +End Function + +Function ValidSourceExt( ext$ ) + Select ext.ToLower() + Case "bmx","i" + Case "c","m","h" + Case "cpp","cxx","mm","hpp","hxx" + Case "s","asm" + Default + Return False + End Select + Return True +End Function + +Function ParseSourceFile:TSourceFile( path$ ) + + If FileType(path)<>FILETYPE_FILE Return + + Local ext$=ExtractExt( path ).ToLower() + If Not ValidSourceExt( ext ) Return + + Local file:TSourceFile=New TSourceFile + file.ext=ext + file.path=path + + Local str$=LoadText( path ) + + Local pos,in_rem,cc=True + + While pos-1 line=line[..n] + + If Not line Continue + + Local lline$=line.Tolower() + + If in_rem + If lline[..6]="endrem" Or lline[..7]="end rem" + in_rem=False + EndIf + Continue + Else If lline[..3]="rem" + in_rem=True + Continue + EndIf + + If lline[..1]="?" + Local t$=lline[1..].Trim() + + Local cNot + If t.StartsWith( "not " ) + cNot=True + t=t[4..].Trim() + EndIf + + Select t + Case "" + cc=True + Case "debug" + cc=opt_debug + Case "threaded" + cc=opt_threaded +?x86 + Case "x86" cc=opt_arch="x86" +?ppc + Case "ppc" cc=opt_arch="ppc" +? +?Win32 + Case "win32" cc=True + Case "win32x86" cc=opt_arch="x86" + Case "win32ppc" cc=opt_arch="ppc" +?Linux + Case "linux" cc=True + Case "linuxx86" cc=opt_arch="x86" + Case "linuxppc" cc=opt_arch="ppc" +?MacOS + Case "macos" cc=True + Case "macosx86" cc=opt_arch="x86" + Case "macosppc" cc=opt_arch="ppc" +? + Default + cc=False + End Select + If cNot cc=Not cc + Continue + EndIf + + If Not cc Continue + + If Not CharIsAlpha( lline[0] ) Continue + + Local i=1 + While i1 And val[0]=34 And val[val.length-1]=34 + qval=val[1..val.length-1] + EndIf + + Select key + Case "module" + file.modid=val.ToLower() + Case "framework" + file.framewk=val.ToLower() + Case "import" + If qval + file.imports.AddLast qval + Else + file.modimports.AddLast val.ToLower() + EndIf + Case "incbin" + If qval + file.incbins.AddLast qval + EndIf + Case "include" + If qval + file.includes.AddLast qval + EndIf + Case "moduleinfo" + If qval + file.info.AddLast qval + If mod_opts mod_opts.addOption(qval) ' BaH + EndIf + End Select + Case "c","m","h","cpp","cxx","hpp","hxx" + If line[..8]="#include" + Local val$=line[8..].Trim(),qval$,qext$ + If val.length>1 And val[0]=34 And val[val.length-1]=34 + qval=val[1..val.length-1] + EndIf + If qval + file.includes.AddLast qval + EndIf + EndIf + End Select + + Wend + + Return file + +End Function diff --git a/src/bmk/bmk_util.bmx b/src/bmk/bmk_util.bmx new file mode 100644 index 0000000..5c122d8 --- /dev/null +++ b/src/bmk/bmk_util.bmx @@ -0,0 +1,359 @@ + +Strict + +Import "bmk_config.bmx" + +'OS X Nasm doesn't work? Used to produce incorrect reloc offsets - haven't checked for a while +Const USE_NASM=False + +Const CC_WARNINGS=False'True + +Type TModOpt ' BaH + Field cc_opts:String = "" + Field ld_opts:TList = New TList + + Method addOption(qval:String) + If qval.startswith("CC_OPTS") Then + cc_opts:+ " " + qval[qval.find(":") + 1..].Trim() + ElseIf qval.startswith("LD_OPTS") Then + Local opt:String = qval[qval.find(":") + 1..].Trim() + + If opt.startsWith("-L") Then + opt = "-L" + CQuote(opt[2..]) + End If + + ld_opts.addLast opt + End If + End Method + + Method hasCCopt:Int(value:String) + Return cc_opts.find(value) >= 0 + End Method + + Method hasLDopt:Int(value:String) + For Local opt:String = EachIn ld_opts + If opt.find(value) >= 0 Then + Return True + End If + Next + Return False + End Method + + Function setPath:String(value:String, path:String) + Return value.Replace("%PWD%", path) + End Function + +End Type + +Global mod_opts:TModOpt ' BaH + +Function Match( ext$,pat$ ) + Return (";"+pat+";").Find( ";"+ext+";" )<>-1 +End Function + +Function HTTPEsc$( t$ ) + t=t.Replace( " ","%20" ) + Return t +End Function + +Function Sys( cmd$ ) + If opt_verbose + Print cmd + Else If opt_dumpbuild + Local p$=cmd + p=p.Replace( BlitzMaxPath()+"/","./" ) + WriteStdout p+"~n" + Local t$="mkdir " + If cmd.StartsWith( t ) And FileType( cmd[t.length..] ) Return + EndIf + Return system_( cmd ) +End Function + +Function CQuote$( t$ ) + If t And t[0]=Asc("-") Return t + For Local i=0 Until t.length + If t[i]=Asc(".") Continue + If t[i]=Asc("/") Continue +?Win32 + If t[i]=Asc("\") Continue +? + If t[i]=Asc("_") Or t[i]=Asc("-") Continue + If t[i]>=Asc("0") And t[i]<=Asc("9") Continue + If t[i]>=Asc("A") And t[i]<=Asc("Z") Continue + If t[i]>=Asc("a") And t[i]<=Asc("z") Continue + Return "~q"+t+"~q" + Next + Return t +End Function + +Function Ranlib( dir$ ) + ' +?MacOS + If macos_version>=$1040 Return +? + ' + For Local f$=EachIn LoadDir( dir ) + Local p$=dir+"/"+f + Select FileType( p ) + Case FILETYPE_DIR + Ranlib p + Case FILETYPE_FILE + If ExtractExt(f).ToLower()="a" Sys "ranlib "+p + End Select + Next +End Function + +Function Assemble( src$,obj$ ) + DeleteFile obj + Local cmd$ +?MacOS + If opt_arch="ppc" + cmd="as -arch ppc" + Else + If USE_NASM + cmd="nasm -f macho" + Else + cmd="as -arch i386" + EndIf + EndIf + cmd:+" -W -o "+CQuote(obj)+" "+CQuote(src); +?Win32 + cmd$=CQuote(BlitzMaxPath()+"/bin/fasm")+" "+CQuote(src)+" "+CQuote(obj) +?Linux + cmd$=CQuote(BlitzMaxPath()+"/bin/fasm")+" -m32768 "+CQuote(src)+" "+CQuote(obj) +? + If Sys( cmd ) + Throw "Build Error: Failed to assemble "+src + EndIf +End Function + +Function CompileC( src$,obj$,opts$ ) + DeleteFile obj + + Local t$=getenv_( "BMK_CC_OPTS" ) + If t opts:+" "+t + + Local cmd$="gcc" + If ExtractExt(src)="cpp" Or ExtractExt(src)="cc" Or ExtractExt(src)="cxx" Or ExtractExt(src)="mm" + cmd="g++" + Else + If CC_WARNINGS opts:+" -Wimplicit-function-declaration" + EndIf + + If Not CC_WARNINGS opts:+" -w" + +?MacOS + If opt_arch="ppc" + opts:+" -arch ppc" + Else + opts:+" -arch i386" + EndIf + If macos_version>=$1070 'Lion? + opts:+" -mmacosx-version-min=10.4" '...can build for Tiger++ + Else If macos_version>=$1040 'Tiger? + opts:+" -mmacosx-version-min=10.3" '...can build for Panther++ + EndIf +?Win32 + If Not mod_opts Or Not mod_opts.hasCCopt("-march") + opts:+" -march=pentium" + EndIf + opts:+" -ffast-math" +?Linux + opts:+" -m32 -mfancy-math-387 -fno-strict-aliasing" +? + If mod_opts + If Not mod_opts.hasCCopt("-fexceptions") + opts:+" -fno-exceptions" + EndIf + opts:+ " " + mod_opts.cc_opts ' BaH + Else + opts:+" -fno-exceptions" + EndIf + + cmd:+opts+" -c -o "+CQuote(obj)+" "+CQuote(src) + + If Sys( cmd ) + Throw "Build Error: failed to compile "+src + EndIf +End Function + +Function CompileBMX( src$,obj$,opts$ ) + DeleteFile obj + + Local azm$=StripExt(obj)+".s" +?MacOs + Local cmd$=CQuote(BlitzMaxPath()+"/bin/bcc")+opts+" -o "+CQuote(azm)+" "+CQuote(src) +?Win32 + Local cmd$=CQuote(BlitzMaxPath()+"/bin/bcc")+opts+" -o "+CQuote(azm)+" "+CQuote(src) +?Linux + Local cmd$=CQuote(BlitzMaxPath()+"/bin/bcc")+opts+" -o "+CQuote(azm)+" "+CQuote(src) +? + If Sys( cmd ) + Throw "Build Error: failed to compile "+src + EndIf +?MacOs + If opt_arch="x86" + If Not USE_NASM + Local cmd$=CQuote(BlitzMaxPath()+"/bin/fasm2as")+" "+CQuote(azm) + If Sys( cmd ) Throw "Fasm2as failed - please contact BRL!" + EndIf + EndIf +? + Assemble azm,obj + +End Function + +Function CreateArc( path$ , oobjs:TList ) + DeleteFile path + Local cmd$,t$ +?Win32 + For t$=EachIn oobjs + If Len(cmd)+Len(t)>1000 + If Sys( cmd ) + DeleteFile path + Throw "Build Error: Failed to create archive "+path + EndIf + cmd="" + EndIf + If Not cmd cmd="ar -r "+CQuote(path) + cmd:+" "+CQuote(t) + Next +?MacOS + cmd="libtool -o "+CQuote(path) + For Local t$=EachIn oobjs + cmd:+" "+CQuote(t) + Next +?Linux + For Local t$=EachIn oobjs + If Len(cmd)+Len(t)>1000 + If Sys( cmd ) + DeleteFile path + Throw "Build Error: Failed to create archive "+path + EndIf + cmd="" + EndIf + If Not cmd cmd="ar -r "+CQuote(path) + cmd:+" "+CQuote(t) + Next +? + If cmd And Sys( cmd ) + DeleteFile path + Throw "Build Error: Failed to create archive "+path + EndIf +End Function + +Function LinkApp( path$,lnk_files:TList,makelib ) + DeleteFile path + + Local cmd$ + Local files$ + Local tmpfile$=BlitzMaxPath()+"/tmp/ld.tmp" +?MacOS + cmd="g++" + + If opt_arch="ppc" + cmd:+" -arch ppc" + Else + cmd:+" -arch i386 -read_only_relocs suppress" + EndIf + + If macos_version>=$1070 'Lion? + cmd:+" -mmacosx-version-min=10.4" '...can build for Tiger++ + Else If macos_version>=$1040 'Tiger? + cmd:+" -mmacosx-version-min=10.3" '...can build for Panther++ + EndIf + + cmd:+" -o "+CQuote( path ) + cmd:+" "+CQuote( "-L"+CQuote( BlitzMaxPath()+"/lib" ) ) + + If Not opt_dumpbuild cmd:+" -filelist "+CQuote( tmpfile ) + + For Local t$=EachIn lnk_files + If opt_dumpbuild Or (t[..1]="-") + cmd:+" "+t + Else + files:+t+Chr(10) + EndIf + Next + cmd:+" -lSystem -framework CoreServices -framework CoreFoundation" +?Win32 + cmd=CQuote(BlitzMaxPath()+"/bin/ld.exe")+" -s -stack 4194304" 'symbol stripping enabled + If opt_apptype="gui" cmd:+" -subsystem windows" + If makelib cmd:+" -shared" + + cmd:+" -o "+CQuote( path ) + cmd:+" "+CQuote( "-L"+CQuote( BlitzMaxPath()+"/lib" ) ) + + If makelib + Local imp$=StripExt(path)+".a" + Local def$=StripExt(path)+".def" + If FileType( def )<>FILETYPE_FILE Throw "Cannot locate .def file" + cmd:+" "+def + cmd:+" --out-implib "+imp + files:+"~n"+CQuote( BlitzMaxPath()+"/lib/dllcrt2.o" ) + Else + files:+"~n"+CQuote( BlitzMaxPath()+"/lib/crtbegin.o" ) + files:+"~n"+CQuote( BlitzMaxPath()+"/lib/crt2.o" ) + EndIf + + 'Unholy!!!!! + Local xpmanifest$ + For Local f$=EachIn lnk_files + Local t$=CQuote( f ) + If opt_dumpbuild Or (t[..1]="-" And t[..2]<>"-l") + cmd:+" "+t + Else + If f.EndsWith( "/win32maxguiex.mod/xpmanifest.o" ) + xpmanifest=t + Else + files:+"~n"+t + EndIf + EndIf + Next + + If xpmanifest files:+"~n"+xpmanifest + + cmd:+" "+CQuote( tmpfile ) + + files:+"~n-lgdi32 -lwsock32 -lwinmm -ladvapi32" + files:+" -lstdc++ -lgcc -lmingwex -lmingw32 -lmoldname -lmsvcrt -luser32 -lkernel32" + + If Not makelib + files:+" "+CQuote( BlitzMaxPath()+"/lib/crtend.o" ) + EndIf + + files="INPUT("+files+")" +?Linux + + cmd="g++" + cmd:+" -m32 -s -Os -pthread" + cmd:+" -o "+CQuote( path ) + cmd:+" "+CQuote( tmpfile ) + cmd:+" -L/usr/lib32" + cmd:+" -L/usr/X11R6/lib" + cmd:+" -L/usr/lib" + cmd:+" -L"+CQuote( BlitzMaxPath()+"/lib" ) + + For Local t$=EachIn lnk_files + t=CQuote(t) + If opt_dumpbuild Or (t[..1]="-" And t[..2]<>"-l") + cmd:+" "+t + Else + files:+" "+t + EndIf + Next + + files="INPUT("+files+")" +? + Local t$=getenv_( "BMK_LD_OPTS" ) + If t + cmd:+" "+t + EndIf + + Local stream:TStream=WriteStream( tmpfile ) + stream.WriteBytes files.ToCString(),files.length + stream.Close + + If Sys( cmd ) Throw "Build Error: Failed to link "+path + +End Function diff --git a/src/bmk/bmk_zap.bmx b/src/bmk/bmk_zap.bmx new file mode 100644 index 0000000..0301fbb --- /dev/null +++ b/src/bmk/bmk_zap.bmx @@ -0,0 +1,138 @@ + +Strict + +Import "bmk_modutil.bmx" +Import "bmk_bank.bmx" +Import "bmk_modinfo.bmx" + +Function Zap( path$,stream:TStream ) + + If Not path Return False + + Local name$=StripDir( path ) + + Local skip=False + + If name[..1]="." + skip=True + Else If name.ToLower().EndsWith( ".bak" ) + skip=True + EndIf + + If skip + stream.WriteLine "" + Return True + EndIf + + Local mode=FileMode( path ) + + Select FileType(path) + Case FILETYPE_NONE + Print "Error zapping file "+path + Return + Case FILETYPE_FILE + Local size=FileSize(path) + stream.WriteLine name + stream.WriteLine mode + stream.WriteLine size + Local from_stream:TStream=ReadStream(path) + CopyBytes from_stream,stream,size + from_stream.Close + Case FILETYPE_DIR + Local dir$[]=LoadDir( path ) + Local size=Len( dir ) + stream.WriteLine name + stream.WriteLine -mode + stream.WriteLine size + For Local t$=EachIn dir + If Not Zap( path+"/"+t,stream ) Return + Next + End Select + + Return True + +End Function + +Function Unzap( dir$,stream:TStream ) + + Local name$=stream.ReadLine() + If Not name Return True + + Local mode=Int( stream.ReadLine() ) + Local size=Int( stream.ReadLine() ) + + Local path$=dir+"/"+name + + If mode<0 + mode=-mode + CreateDir path + For Local k=0 Until size + If Not Unzap( path,stream ) Return + Next + Else + DeleteFile path + Local to_stream:TStream=WriteStream(path) + CopyBytes stream,to_stream,size + to_stream.Close + EndIf + + SetFileMode path,mode + Return True + +End Function + +Function ZapMod( name$,stream:TStream ) + + Local path$=ModuleInterface( name,"release."+cfg_platform+"."+opt_arch ) + + If FileType(path)<>FILETYPE_FILE + Print "Failed to find module" + Return + EndIf + + Local src:TSourceFile=ParseSourceFile( path ) + stream.WriteLine "Module: "+name + For Local t$=EachIn src.info + stream.WriteLine t + Next + stream.WriteLine "" + + Local bank:TBank=TBank.Create(0) + Local bank_stream:TStream=TBankStream.Create( bank ) + If Not Zap( ModulePath(name),bank_stream ) Throw "Failed to publish module" + bank_stream.Close + + bank=CompressBank( bank ) + bank_stream=TBankStream.Create( bank ) + CopyStream bank_stream,stream + bank_stream.Close + +End Function + +Function UnzapMod( stream:TStream ) + + Local modinfo:TModInfo=TModInfo.CreateFromStream( stream ) + + Local path$=ModulePath( modinfo.name ) + If Not CreateDir( path,True ) Throw "Unable to create module directory" + DeleteDir path,True + + Local bank:TBank=TBank.Create(0) + Local bank_stream:TStream=TBankStream.Create( bank ) + CopyStream stream,bank_stream + bank_stream.Close + + bank=UncompressBank( bank ) + bank_stream=TBankStream.Create( bank ) + If Not Unzap( ExtractDir(path),bank_stream ) + Print "Failed to Unzap module" + Return + EndIf + bank_stream.Close + +?MacOS + Ranlib path +? + Return True + +End Function diff --git a/src/bmk/macos.icns b/src/bmk/macos.icns new file mode 100644 index 0000000..b712495 Binary files /dev/null and b/src/bmk/macos.icns differ diff --git a/src/docmods/bmxtoker.bmx b/src/docmods/bmxtoker.bmx new file mode 100644 index 0000000..3278e2c --- /dev/null +++ b/src/docmods/bmxtoker.bmx @@ -0,0 +1,400 @@ +Strict + +Import BRL.Map +Import BRL.Stream + +Private + +Function ReadTextStream:TStream( url:Object ) + + Local format,size,c,d,e + Local stream:TStream=ReadStream( url ) + If Not stream Return + + If Not stream.Eof() + c=stream.ReadByte() + size:+1 + If Not stream.Eof() + d=stream.ReadByte() + size:+1 + If c=$fe And d=$ff + format=TTextStream.UTF16BE + Else If c=$ff And d=$fe + format=TTextStream.UTF16LE + Else If c=$ef And d=$bb + If Not stream.Eof() + e=stream.ReadByte() + size:+1 + If e=$bf format=TTextStream.UTF8 + EndIf + EndIf + EndIf + EndIf + + If format Return TTextStream.Create( stream,format ) + + stream.Close + + Return ReadStream( url ) + +End Function + +Public + +Function TPrint( t$ ) + Local p + For Local i=0 Until t.length + If t[i]<256 Continue + 'unicode char! + StandardIOStream.WriteString t[p..i] + StandardIOStream.WriteString "&#"+t[i]+";" + p=i+1 + Next + Print t[p..] +End Function + +'----- Simple BMX Parser ----- + +Const T_EOF= -1 +Const T_EOL= 10 + +Const T_IDENT= $10001 +Const T_INTLIT= $10002 +Const T_FLOATLIT= $10003 +Const T_STRINGLIT= $10004 +Const T_STRINGERR= $10005 + +Const T_REM= $20001 +Const T_ENDREM= $20002 +Const T_FUNCTION= $20003 +Const T_ENDFUNCTION=$20004 +Const T_TYPE= $20005 +Const T_ENDTYPE= $20006 +Const T_CONST= $20007 +Const T_METHOD= $20008 +Const T_ENDMETHOD= $20009 +Const T_GLOBAL= $2000a +Const T_INCLUDE= $2000b ' Added by BaH - 01/06/2006 +Const T_IMPORT= $2000d +Const T_FIELD= $2000e +Const T_EXTENDS= $2000f +Const T_ABSTRACT= $20010 +Const T_FINAL= $20011 +Const T_MODULE= $2000c +Const T_MODULEINFO= $20012 + +Const T_DOTDOT= $30001 +Const T_ARRAYDECL= $30002 + +Const T_KEYWORD= $40000 + +Type TIntValue + Field value:Int +End Type + +Function IntValue:TIntValue( value ) + Local t:TIntValue=New TIntValue + t.value=value + Return t +End Function + +Function IsSpace( char ) + Return char<=Asc(" ") And char<>Asc("~n") +End Function + +Function IsAlpha( char ) + Return ( char>=Asc("a") And char<=Asc("z") ) Or ( char>=Asc("A") And char<=Asc("Z") ) +End Function + +Function IsNumeric( char ) + Return char>=Asc("0") And char<=Asc("9") +End Function + +Function IsAlphaNumeric( char ) + Return IsAlpha( char ) Or IsNumeric( char ) +End Function + +Type TBmxToker + + Field _filename:String ' Added by BaH - 25/05/2006 + + Field _spc + Field _pos,_line$ + Field _toke,_text$ + Field _stream:TStream + + Global _keywords:TMap + + Method Delete() + Close + End Method + + Method Bump() + + If _toke=T_EOF Return _toke + + If _pos>=_line.length + _pos=0 + If _stream.Eof() + _toke=T_EOF + _text="" + Return + EndIf + _line=_stream.ReadLine().Trim()+"~n" + EndIf + + Local from=_pos + While _pos<_line.length And IsSpace( _line[_pos] ) + _pos:+1 + Wend + + If _spc And _pos<>from + _text=_line[from.._pos] + _toke=Asc(" ") + Return _toke + EndIf + + from=_pos + Local char=_line[_pos] + _pos:+1 + + If char=Asc("'") + _pos=_line.length + _toke=T_EOL + Else If char=Asc("~n") + _toke=T_EOL + Else If isAlpha(char) Or char=Asc("_") + While IsAlphaNumeric(_line[_pos]) Or _line[_pos]=Asc("_") + _pos:+1 + Wend + _toke=T_IDENT + Local id$=_line[from.._pos].ToLower() + If id="end" And _line[_pos]=Asc(" ") And IsAlpha(_line[_pos+1]) + Local t_pos=_pos+2 + While IsAlphaNumeric(_line[t_pos]) Or _line[t_pos]=Asc("_") + t_pos:+1 + Wend + Local id$="end"+_line[_pos+1..t_pos].ToLower() + Local v:TIntValue=TIntValue( _keywords.ValueForKey( id ) ) + If v + _pos=t_pos + _toke=v.value + EndIf + EndIf + If _toke=T_IDENT + Local v:TIntValue=TIntValue( _keywords.ValueForKey( id ) ) + If v _toke=v.value + If _toke=T_REM + _text="" + Repeat + If _stream.Eof() + _pos=0 + _line="" + Return _toke + EndIf + _line=_stream.ReadLine().Trim()+"~n" + If _line[..6].ToLower()="endrem" Or _line[..7].ToLower()="end rem" Exit + _text:+_line + Forever + _pos=_line.length + Return _toke + Else + ' Complete lines if they continue onto other lines - BaH 03/09/2006 + If _toke = T_FUNCTION Or _toke = T_METHOD Or _toke = T_CONST Or _toke = T_GLOBAL Or _toke = T_FIELD Then + If _line.find("..") >= 0 Then + _line = getFullLine() + End If + End If + EndIf + EndIf + Else If IsNumeric(char) + While IsNumeric(_line[_pos]) + _pos:+1 + Wend + _toke=T_INTLIT + If _line[_pos]=Asc(".") + _pos:+1 + While IsNumeric(_line[_pos]) + _pos:+1 + Wend + _toke=T_FLOATLIT + EndIf + Else If char=Asc("~q") + While _line[_pos]<>Asc("~q") And _line[_pos]<>Asc("~n") + _pos:+1 + Wend + If _line[_pos]=Asc("~q") + _pos:+1 + _toke=T_STRINGLIT + Else + _toke=T_STRINGERR + EndIf + Else + _toke=char + EndIf + + _text=_line[from.._pos] + + Return _toke + + End Method + + ' Completes a line that takes up more than one actual line - BaH 03/09/2006 + Method getFullLine:String() + Local first:Int = True + Local fullline:String + Local line:String = _line + Local pos:Int = 0 + Local from:Int + + #loop + Repeat + + If Not first Then + If _stream.Eof() + pos=0 + line="" + Return line + EndIf + line = _stream.ReadLine().Trim()+"~n" + End If + + first = False + + If line.tolower().Trim() = "rem" Then + Repeat + If _stream.Eof() + pos=0 + line="" + Return fullline + EndIf + line = _stream.ReadLine().Trim()+"~n" + If line[..6].ToLower()="endrem" Or line[..7].ToLower()="end rem" Then + Continue loop + End If + Forever + End If + + pos = 0 + from = pos + While pos < line.length And IsSpace( line[pos] ) + pos:+1 + Wend + + from = pos + + Local char:Int = line[pos] + pos:+1 + While char <> Asc("~n") + + If char = Asc(".") And line[pos] = Asc(".") Then + fullline:+ line[from..pos-1] + Exit + End If + + If char = Asc("'") Then + Exit + End If + + char=line[pos] + pos:+1 + Wend + + If char = Asc("~n") Then + fullline :+ line[from..pos-1] + Exit + End If + + Forever + + Return fullline + End Method + + Method Curr() + Return _toke + End Method + + Method Text$() + Return _text + End Method + + Method Line$() + Return _line + End Method + + Method Parse$( toke ) + If Curr()<>toke Throw "Unexpected token" + Local t$=Text() + Bump + Return t + End Method + + Method CParse$( toke ) + If Curr()<>toke Return + Local t$=Text() + Bump + Return t + End Method + + Method ParseUntil$( toke ) + Local t$ + While Curr()<>toke + If Curr()=T_EOF Throw "Unexpected EOF" + t:+Text() + Bump + Wend + Bump + Return t + End Method + + Method Spaces( enable ) + If enable + _spc:+1 + Else + _spc:-1 + EndIf + End Method + + Method Close() + If _stream _stream.Close + _stream=Null + End Method + + Function CreateKeywords() + If _keywords Return + Function kw( id$,toke ) + _keywords.insert id,IntValue(toke) + End Function + _keywords=New TMap + kw "rem",T_REM + kw "endrem",T_ENDREM + kw "function",T_FUNCTION + kw "endfunction",T_ENDFUNCTION + kw "method",T_METHOD + kw "endmethod",T_ENDMETHOD + kw "const",T_CONST + kw "global",T_GLOBAL + kw "include",T_INCLUDE ' Added by BaH - 01/06/2006 + kw "import",T_IMPORT + kw "field",T_FIELD + kw "type",T_TYPE + kw "endtype",T_ENDTYPE + kw "extends",T_EXTENDS + kw "abstract",T_ABSTRACT + kw "final",T_FINAL + kw "module",T_MODULE + kw "moduleinfo",T_MODULEINFO + End Function + + Function Create:TBmxToker( url:Object ) + CreateKeywords + Local stream:TStream=ReadTextStream( url ) + If Not stream Throw "Unable to read stream: "+url.ToString() + Local t:TBmxToker=New TBmxToker + t._filename = url.ToString() ' Added by BaH - 25/05/2006 + t._stream=stream + t.Bump + Return t + End Function + +End Type diff --git a/src/docmods/dochistory.bmx b/src/docmods/dochistory.bmx new file mode 100644 index 0000000..ce84b6d --- /dev/null +++ b/src/docmods/dochistory.bmx @@ -0,0 +1,180 @@ + +Strict + +Import "docparser.bmx" + +Local docs:TDocs=ParseMods() + +docs.Sort + +DocModHistory docs + +End + +If AppArgs.length=2 + Select AppArgs[1].ToLower() + Case "sync" + SyncDocs docs + Case "history" + DocModHistory docs + End Select +Else + DocMods docs + SyncDocs docs +EndIf + +' spit out versions.doc format history + + +Function DocModHistory( docs:TDocs ) + + Local history$=LoadText("history120.txt") + +' Local stdio:TStream=StandardIOStream +' StandardIOStream=WriteFile( "commands.html" ) + + For Local t:TDocs=EachIn docs.kids + If t.kind<>T_MODULE Continue + For Local info$=EachIn t.infos + If info[info.length-8..]<>"Release~q" + If info[..8]="~qHistory" + Local h$="+ ("+t.ident+") "+info[10..info.length-1] + If Not Instr(history,h) TPrint h + EndIf + EndIf + Next + + Next + +' StandardIOStream.Close +' StandardIOStream=stdio + +End Function + + +Function ParseMods:TDocs() + + Local docs:TDocs=New TDocs + + Local mods:TList=EnumModules() + + For Local modid$=EachIn mods + + Local ident$=ModuleIdent( modid ) + Local modDir$=ModulePath( modid ) + Local bmxFile$=ModuleSource( modid ) + Local docDir$=modDir+"/doc" + + If FileType( modDir+"/"+ident+".bmx" )=FILETYPE_FILE + If FileType( docDir )<>FILETYPE_DIR + CreateDir docDir + If FileType( docDir )<>FILETYPE_DIR + TPrint "Failed to created directory:"+docDir + Continue + EndIf + EndIf + + Local toker:TBMXToker=TBMXToker.Create( bmxFile ) + + Local parser:TDocParser=TDocParser.WithToker( toker ) + + parser.Parse docs + + parser.Close + + EndIf + + Next + + Return docs + +End Function + +Function DocMods( docs:TDocs ) + + For Local t:TDocs=EachIn docs.kids + + If t.kind<>T_MODULE Continue + + ChangeDir ModulePath( t.ident.tolower() )+"/doc" 'linux fix for "BRL." case problem + + Local stdio:TStream=StandardIOStream + StandardIOStream=WriteFile( "commands.html" ) + + t.CacheTexts ' pre cache of text for output (allows us to use it for summaries etc) - BaH 03/09/2006 + t.EmitHtml + + StandardIOStream.Close + StandardIOStream=stdio + + Next +End Function + +Function SyncDocs( docs:TDocs ) + + Local comms:TList=New TList + Local index:TList=New TList + + Local stdio:TStream=StandardIOStream + StandardIOStream=WriteFile( BlitzMaxPath()+"/doc/bmxmods/navbar.html" ) + + TPrint "" + TPrint "" + TPrint "" + TPrint "" + + TPrint "Module reference
" + + For Local t:TDocs=EachIn docs.kids + + If t.kind<>T_MODULE Continue + + Local modid$=t.ident.ToLower() + Local modln$=modid.Replace(".","_") + Local moddesc$=t.bbdoc[6..].Trim() + Local i=moddesc.Find("~n") + If i<>-1 moddesc=moddesc[..i] + + Local url$="../../mod/"+modid.Replace(".",".mod/")+".mod/doc/commands.html" + + TPrint ""+moddesc+"
" + TPrint "
" + For Local p:TDocs=EachIn t.kids + ' kind is Type and is not doc'd and there are no doc'd kids + If p.kind = T_TYPE And (Not p.bbdoc And p.kids.count() = 0) Then + Continue + End If + Local turl$=url+"#"+p.ident + TPrint " "+p.ident+"
" + index.AddLast p.ident+":"+turl + Local i=p.proto.Find( " " ) + If i<>-1 comms.AddLast p.proto[i+1..].Trim()+"|"+turl[5..] + Next + TPrint "
" + + Next + + TPrint "
" + TPrint "Alphabetic index
" + + Local arr:Object[]=index.ToArray() + arr.Sort + For Local link$=EachIn arr + Local i=link.Find( ":" ) + If i=-1 Throw "chunks" + Local ident$=link[..i],url$=link[i+1..] + TPrint ""+ident+"
" + Next + + TPrint "" + + StandardIOStream.Close + StandardIOStream=WriteStream( BlitzMaxPath()+"/doc/bmxmods/commands.txt" ) + For Local t$=EachIn comms + TPrint t + Next + StandardIOStream.Close + StandardIOStream=stdio + +End Function + diff --git a/src/docmods/docmods.bmx b/src/docmods/docmods.bmx new file mode 100644 index 0000000..b972a6f --- /dev/null +++ b/src/docmods/docmods.bmx @@ -0,0 +1,157 @@ + +Rem + +Note: docmods is now only used to build 3rd party modules. + +BRL, MAXGUI and PUB mods are built by new makedocs. + +End Rem + +Strict + +Framework brl.basic + +Import "docparser.bmx" + +CreateDir BlitzMaxPath()+"/doc/bmxmods",True + +Local docs:TDocs=ParseMods() + +docs.Sort + +If AppArgs.length=2 And AppArgs[1].ToLower()="sync" + SyncDocs docs +Else + DocMods docs + SyncDocs docs +EndIf + +Function ParseMods:TDocs() + + Local docs:TDocs=New TDocs + + Local mods:TList=EnumModules() + + For Local modid$=EachIn mods + + If modid.StartsWith( "brl." ) Or modid.StartsWith( "pub." ) Or modid.StartsWith( "maxgui." ) Continue + + Local ident$=ModuleIdent( modid ) + Local modDir$=ModulePath( modid ) + Local bmxFile$=ModuleSource( modid ) + Local docDir$=modDir+"/doc" + + If FileType( modDir+"/"+ident+".bmx" )=FILETYPE_FILE + If FileType( docDir )<>FILETYPE_DIR + CreateDir docDir + If FileType( docDir )<>FILETYPE_DIR + Print "Failed to created directory:"+docDir + Continue + EndIf + EndIf + + Local toker:TBMXToker=TBMXToker.Create( bmxFile ) + + Local parser:TDocParser=TDocParser.WithToker( toker ) + + parser.Parse docs + + parser.Close + + EndIf + + Next + + Return docs + +End Function + +Function DocMods( docs:TDocs ) + + For Local t:TDocs=EachIn docs.kids + + If t.kind<>T_MODULE Continue + + ChangeDir ModulePath( t.ident.tolower() )+"/doc" 'linux fix for "BRL." case problem + + Local stdio:TStream=StandardIOStream + StandardIOStream=WriteFile( "commands.html" ) + + t.CacheTexts ' pre cache of text for output (allows us to use it for summaries etc) - BaH 03/09/2006 + t.EmitHtml + + StandardIOStream.Close + StandardIOStream=stdio + + Next +End Function + +Function SyncDocs( docs:TDocs ) + + Local comms:TList=New TList + Local index:TList=New TList + + Local stdio:TStream=StandardIOStream + StandardIOStream=WriteFile( BlitzMaxPath()+"/doc/bmxmods/navbar.html" ) + + TPrint "" + TPrint "" + TPrint "" + TPrint "" + + TPrint "Module reference
" + + For Local t:TDocs=EachIn docs.kids + + If t.kind<>T_MODULE Continue + + Local modid$=t.ident.ToLower() + Local modln$=modid.Replace(".","_") + Local moddesc$=t.bbdoc[6..].Trim() + Local i=moddesc.Find("~n") + If i<>-1 moddesc=moddesc[..i] + + Local url$="../../mod/"+modid.Replace(".",".mod/")+".mod/doc/commands.html" + + TPrint ""+moddesc+"
" + TPrint "
" + For Local p:TDocs=EachIn t.kids + ' kind is Type and is not doc'd and there are no doc'd kids + If p.kind = T_TYPE And (Not p.bbdoc And p.kids.count() = 0) Then + Continue + End If + Local turl$=url+"#"+p.ident + TPrint " "+p.ident+"
" + index.AddLast p.ident+":"+turl + Local i=p.proto.Find( " " ) + If i<>-1 comms.AddLast p.proto[i+1..].Trim()+"|"+turl[5..] + Next + TPrint "
" + + Next + + TPrint "
" + TPrint "Alphabetic index
" + + Local arr:Object[]=index.ToArray() + + arr.Sort + For Local link$=EachIn arr + Local i=link.Find( ":" ) + If i=-1 Throw "chunks" + Local ident$=link[..i],url$=link[i+1..] + TPrint ""+ident+"
" + Next + + TPrint "" + + StandardIOStream.Close + StandardIOStream=WriteStream( BlitzMaxPath()+"/doc/bmxmods/commands.txt" ) + For Local t$=EachIn comms + Print t + Next + StandardIOStream.Close + StandardIOStream=stdio + +End Function + diff --git a/src/docmods/docparser.bmx b/src/docmods/docparser.bmx new file mode 100644 index 0000000..ea4b0ec --- /dev/null +++ b/src/docmods/docparser.bmx @@ -0,0 +1,683 @@ +Strict + +Import BRL.StandardIO +Import BRL.MaxUtil + +Import "bmxtoker.bmx" + +Function FormatTags( t$ Var,bbTag$,htmlTag$ ) + Local i + Repeat + i=t.Find( bbTag,i ) + If i=-1 Exit + + If i And t[i-1]>32 + i:+1 + Continue + EndIf + + Local e + If i"+t[i+2..e]+"" + t=t[..i]+q+t[e+1..] + i:+q.length + + Else + e=i+1 + While eAsc("_") And Not IsAlphaNumeric(c) Exit + e:+1 + Wend + Local q$="<"+htmlTag+">"+t[i+1..e]+"" + t=t[..i]+q+t[e..] + i:+q.length + EndIf + Forever +End Function + +Function FindIdent( pre$,text$,i Var,e Var ) + + i=text.Find( pre,i ) + + If i=-1 Return False + + If i>0 And text[i-1]>32 Return False + + e=i+1 + While eAsc("_") And Not IsAlphaNumeric(c) Exit + e:+1 + Wend + Return True +End Function + +Function FormatText( t$ Var ) + + If t.length And IsAlphaNumeric( t[t.length-1] ) t:+"." + + Local i,e + + 'do links + i=0 + While FindIdent( "#",t,i,e ) + + While e"+id+"" + Else + ln=""+id+"" + EndIf + + t=t[..i]+ln+t[e..] + i:+ln.length + Wend + + FormatTags t,"@","b" + FormatTags t,"%","i" + FormatTags t,"&","pre" + + 'do tables + i=0 + Repeat + i=t.Find( "~n[",i ) + If i=-1 Exit + + Local i2=t.Find( "~n]",i+3 ) + If i2=-1 Exit + + Local q$=t[i+2..i2] + + q=q.Replace( "* ","" ) + q=q.Replace( " | ","" ) + + q="~n
"+q+"
~n" + + t=t[..i]+q+t[i2+2..] + i:+q.length + + Forever + + 'paras + t=t.Replace( "~n~n","~n

~n" ) + +End Function + +Type TDocs + + Field kind 'T_CONST, T_GLOBAL etc + Field ident$ 'identifier + Field proto$ 'Global/Function etc text + Field bbdoc$ 'rem/endrem bbdoc: text + Field infos:TList=New TList 'ModuleInfo's + Field imports:TList = New TList ' Added by BaH - 25/05/2006 + Field parent:TDocs ' Added by BaH - 25/05/2006 + Field textCache:TTextCache + + Field kids:TList=New TList + + Method Sort() + kids.Sort + For Local t:TDocs=EachIn kids + t.Sort + Next + End Method + + ' Added by BaH - 25/05/2006 + ' Checks for extra references to the same imports... + Method containsImport:Int(_file:String) + If imports.contains(_file) Then + Return True + End If + If parent <> Null Then + Return parent.containsImport(_file) + End If + + Return False + End Method + + Method Compare( with:Object ) + Local t:TDocs=TDocs(with) + + If kind=t.kind + If kind=T_MODULE + Return bbdoc.ToLower().Compare( t.bbdoc.ToLower() ) + EndIf + Return ident.ToLower().Compare( t.ident.ToLower() ) + EndIf + + If kind=T_MODULE Return -1 + If t.kind=T_MODULE Return 1 + + If kind=T_CONST Return -1 + If t.kind=T_CONST Return 1 + + If kind=T_GLOBAL Return -1 + If t.kind=T_GLOBAL Return 1 + + If kind=T_FIELD Return -1 + If t.kind=T_FIELD Return 1 + + If kind=T_METHOD Return -1 + If t.kind=T_METHOD Return 1 + + If kind=T_FUNCTION Return -1 + If t.kind=T_FUNCTION Return 1 + + If kind=T_TYPE Return -1 + If t.kind=T_TYPE Return 1 + + If kind=T_EOL Return -1 + If t.kind=T_EOL Return 1 + + Throw "OOps!" + + End Method + + Method CacheTexts() + If textCache = Null Then + textCache = TTextCache.Create(bbdoc, kind) + + If Not kids.IsEmpty() + Local tkind=0 + For Local doc:TDocs=EachIn kids + doc.CacheTexts() + Next + EndIf + + End If + + End Method + + Method EmitHtml$(summary:Int = False) + Local example$ + + Local stream:TStream=ReadStream( ident+".bmx" ) + If stream + While Not stream.Eof() + example:+stream.ReadLine()+"~n" + Wend + stream.Close + example=example.Trim() + EndIf + + If Not summary Then + Select kind + Case 0 + Case T_MODULE + TPrint ""+textCache.shortdesc+" reference" + TPrint "" + TPrint "" + Local n_consts + Local n_globals + Local n_functions + Local n_types + Local n_keywords:Int + For Local t:TDocs=EachIn kids + Select t.kind + Case T_CONST n_consts:+1 + Case T_GLOBAL n_globals:+1 + Case T_FUNCTION n_functions:+1 + Case T_TYPE + ' Type is doc'd or there are doc'd kids + If t.bbdoc Or t.kids.count() > 0 Then + n_types:+1 + End If + Case T_EOL n_keywords:+1 + End Select + Next + + TPrint "" + TPrint "" + If n_consts TPrint "" + If n_globals TPrint "" + If n_functions TPrint "" + If n_types TPrint "" + If n_keywords TPrint "" + + If Not infos.IsEmpty() + TPrint "" + EndIf + + Local t$=ModuleSource( ident.ToLower() ) + Local i=t.Find( "/mod/" ) + If i<>-1 + t="../../../.."+t[i..] + TPrint "" + EndIf + TPrint "
 "+ident+":ConstantsGlobalsFunctionsTypesKeywordsModinfoSource 
" + + Local stream:TStream=ReadStream( "intro.bbdoc" ) + + If stream + TPrint "

"+textCache.shortdesc+"

" + If textCache.longdesc TPrint textCache.longdesc.Trim() + Else + stream=ReadStream( "intro.html" ) + If Not stream + TPrint "

"+textCache.shortdesc+"

" + If textCache.longdesc TPrint textCache.longdesc.Trim() + EndIf + EndIf + + If stream + Local intro$ + While Not stream.Eof() + intro:+stream.ReadLine()+"~n" + Wend + Local i=intro.Find("") + If i<>-1 + intro=intro[i+6..] + i=intro.find("") + If i<>-1 intro=intro[..i] + EndIf + stream.close + intro=intro.Trim() + FormatText intro + TPrint intro + EndIf + + ' Show summaries + If Not kids.IsEmpty() + Local s:String = Null + Local tkind=0 + Local count:Int = 0 + For Local doc:TDocs=EachIn kids + ' kind is Type and is not doc'd and there are no doc'd kids + If doc.kind = T_TYPE And (Not doc.bbdoc And doc.kids.count() = 0) Then + Continue + End If + + s = "" + + If kind<>T_TYPE And doc.kind<>tkind + count = 0 + If tkind <> 0 Then + If tkind = T_CONST Or tkind = T_GLOBAL Or tkind = T_EOL Then + TPrint "" + End If + TPrint "
" + End If + Select doc.kind + Case T_CONST TPrint "

Constants Summary

" + s + "" + Case T_GLOBAL TPrint "

Globals Summary

" + s + "" + Case T_FUNCTION TPrint "

Functions Summary

" + s + Case T_TYPE TPrint "

Types Summary

" + s + Case T_EOL TPrint "

Keywords Summary

" + s + "" + Default + Continue + End Select + tkind=doc.kind + EndIf + count:+ 1 + If count > 1 Then + If tkind = T_CONST Or tkind = T_GLOBAL Or tkind = T_EOL Then + TPrint ", " + End If + End If + doc.EmitHtml(True) + Next + If s Then + TPrint "" + End If + EndIf + + Default + TPrint "" + TPrint "" + If textCache.returns + TPrint "" + EndIf + If textCache.shortdesc + TPrint "" + EndIf + If textCache.longdesc + TPrint "" + EndIf + If example + TPrint "" + EndIf + TPrint "
"+proto+"
Returns"+textCache.returns+"
Description"+textCache.shortdesc+"
Information"+textCache.longdesc+"
Example
"+example+"
" + End Select + + If kind = T_TYPE Then + ' Show summaries + If Not kids.IsEmpty() + Local s:String = Null + Local tkind=0 + Local count:Int = 0 + For Local doc:TDocs=EachIn kids + s = "" + .. + "" + End If + TPrint "
" + If doc.kind<>tkind + count = 0 + If tkind <> 0 Then + If tkind = T_CONST Or tkind = T_GLOBAL Or tkind = T_EOL Or tkind = T_FIELD Then + TPrint "
" + End If + Select doc.kind + Case T_CONST TPrint s + "Constants Summary" + Case T_FIELD TPrint s + "Fields Summary" + Case T_GLOBAL TPrint s + "Globals Summary" + Case T_FUNCTION TPrint s + "Functions Summary" + Case T_METHOD TPrint s + "Methods Summary" + Default + Continue + End Select + tkind=doc.kind + EndIf + count:+ 1 + If count > 1 Then + If tkind = T_CONST Or tkind = T_GLOBAL Or tkind = T_FIELD Then + TPrint ", " + End If + End If + doc.EmitHtml(True) + Next + If s Then + TPrint "" + End If + EndIf + End If + + If Not kids.IsEmpty() + Local tkind=0 + For Local doc:TDocs=EachIn kids + ' kind is Type and is not doc'd and there are no doc'd kids + If doc.kind = T_TYPE And (Not doc.bbdoc And doc.kids.count() = 0) Then + Continue + End If + + If kind<>T_TYPE And doc.kind<>tkind + TPrint "Constants" + Case T_GLOBAL TPrint " id=globalsdet>Globals" + Case T_FUNCTION TPrint " id=functionsdet>Functions" + Case T_TYPE TPrint " id=typesdet>Types" + Case T_FIELD TPrint ">Fields" + Case T_METHOD TPrint ">Methods" + Case T_EOL TPrint ">Keywords" + End Select + TPrint "" + tkind=doc.kind + EndIf + doc.EmitHtml + If kind<>T_TYPE TPrint "
" + Next + EndIf + Else + Select kind + Case T_CONST, T_GLOBAL, T_FIELD, T_EOL + TPrint "" + ident + "" + Case T_FUNCTION, T_METHOD, T_TYPE + TPrint "" + ident + "" + If textCache.shortdesc + TPrint textCache.shortdesc + Else + TPrint " " + EndIf + TPrint "" + End Select + End If + + + + Select kind + Case T_MODULE + If Not infos.IsEmpty() + TPrint "

Module Information

" + TPrint "" + For Local t$=EachIn infos + t=t[1..t.length-1] + If Not t Continue + Local i=t.Find(":") + If i=-1 Continue + Local key$=t[..i].Trim() + Local val$=t[i+1..].Trim() + TPrint "" + Next + EndIf + TPrint "" + End Select + + End Method + +End Type + +Type TDocParser + + Field toker:TBMXToker + + Method Close() + If Not toker Return + toker.Close + toker=Null + End Method + + ' Added by BaH - 25/05/2006 + Method processImport(parent:TDocs, txt:String) + + If txt.find(".bmx") > 0 Then + + Local importFile:String = ExtractDir(toker._filename) + "/" + txt[1..txt.length-1] + Local _file:String = StripDir(importFile).toLower() + + If Not parent.containsImport(_file) Then + If FileType(importFile) = 1 Then ' exists ! + parent.imports.AddLast(_file) + Local _toker:TBMXToker=TBMXToker.Create(importFile) + Local _parser:TDocParser=TDocParser.WithToker(_toker) + _parser.Parse parent + _parser.Close + End If + End If + End If + + End Method + + Method Parse( parent:TDocs ) + + If Not toker Throw "closed" + + While toker.Curr()<>T_EOF + + If toker.Curr()=T_ENDTYPE + If parent.kind=T_TYPE Return + toker.Bump + Continue + EndIf + + ' Added by BaH - 25/05/2006, modified 01/06/2006 + If toker.Curr()=T_IMPORT Or toker.Curr()=T_INCLUDE Then + If parent.kind=T_MODULE + If toker.Bump()=T_STRINGLIT + processImport(parent, Toker.Text()) + End If + End If + End If + + If toker.Curr()=T_MODULEINFO + If parent.kind=T_MODULE + If toker.Bump()=T_STRINGLIT + parent.infos.AddLast toker.Text() + EndIf + EndIf + toker.Bump + Continue + EndIf + + Local skip:Int = False + Local kind:Int + Local bbdoc$ + + If toker.Curr()<>T_REM + kind = toker.Bump() + + ' Fix to stop fields / methods etc appearing at top of docs if type not doc'd. + If kind = T_TYPE Then + skip = True + Else + Continue + End If + EndIf + + If Not skip Then + If toker.Text()[..6]<>"bbdoc:" + toker.Bump + Continue + EndIf + bbdoc = toker.Text() + + + kind=toker.Bump() + If kind<>T_CONST And kind<>T_GLOBAL And kind<>T_FUNCTION And kind<>T_METHOD.. + And kind<>T_MODULE And kind<>T_TYPE And kind<>T_FIELD And kind<>T_EOL + toker.Bump + Continue + EndIf + End If + + Local ident$,proto$ + If kind=T_EOL + Local i=bbdoc.Find( "keyword:" ) + If i=-1 Continue + ident=bbdoc[i+8..].Replace( "~q","" ) + proto="Keyword "+ident.Trim() + Else + proto=toker.Line() + If toker.Bump()<>T_IDENT Continue + ident=toker.Text() + If toker.Bump()=Asc(".") And toker.Bump()=T_IDENT + ident:+"."+toker.Text() + EndIf + toker.Bump + Select kind + Case T_CONST,T_GLOBAL + Local i=proto.Find( "=" ) + If i<>-1 proto=proto[..i] + Case T_FUNCTION,T_METHOD + Local i=proto.Find( "=" ) + While i<>-1 And proto.Find( ")",i+1 )<>-1 + i=proto.Find( "=",i+1 ) + Wend + If i<>-1 proto=proto[..i] + + + i=proto.toLower().Find( "nodebug" ) + While i<>-1 And proto.Find( ")",i+1 )<>-1 + i=proto.toLower().Find( "nodebug",i+1 ) + Wend + If i<>-1 proto=proto[..i] + + End Select + EndIf + + 'got a valid Doc! + Local docs:TDocs=New TDocs + docs.kind=kind + docs.ident=ident.Trim() + docs.proto=proto.Trim() + docs.bbdoc=bbdoc.Trim() + docs.parent = parent ' Added by BaH - 25/05/2006 + + parent.kids.AddLast docs + + If kind=T_MODULE Or kind=T_TYPE + Parse docs + EndIf + + Wend + + End Method + + Function WithToker:TDocParser( toker:TBmxToker ) + + Local t:TDocParser=New TDocParser + t.toker=toker + Return t + + End Function + +End Type + +Type TTextCache + Field returns:String + Field keyword:String + Field shortdesc:String + Field longdesc:String + Field parameters:TList = New TList + + Function Create:TTextCache(bbdoc:String, kind:Int) + Local this:TTextCache = New TTextCache + + Local d:String = bbdoc + + Local i=d.Find("~n") + If i=-1 i=d.length + this.shortdesc=d[6..i].Trim() + d=d[i+1..].Trim() + If kind<>T_MODULE + FormatText this.shortdesc + EndIf + + If d.Find( "returns:" )=0 + Local i=d.Find("~n") + If i=-1 i=d.length + this.returns=d[8..i].Trim() + d=d[i+1..].Trim() + FormatText this.returns + Else If d.Find( "keyword:" )=0 + Local i=d.Find("~n") + If i=-1 i=d.length + this.keyword=d[8..i].Trim() + d=d[i+1..].Trim() + FormatText this.keyword + EndIf + While d.Find("parameter:") = 0 + Local i=d.Find("~n") + If i=-1 i=d.length + Local param:String=d[10..i].Trim() + d=d[i+1..].Trim() + FormatText param + this.parameters.addLast(param) + Wend + If d.Find( "about:" )=0 + this.longdesc=d[6..].Trim() + FormatText this.longdesc + EndIf + + Return this + End Function +End Type \ No newline at end of file diff --git a/src/fasm2as/fasm2as.bmx b/src/fasm2as/fasm2as.bmx new file mode 100644 index 0000000..1184d0b --- /dev/null +++ b/src/fasm2as/fasm2as.bmx @@ -0,0 +1,245 @@ + +Strict + +Framework brl.basic + +Import Pub.StdC + +Try + +ChangeDir LaunchDir + +If AppArgs.length<>2 And AppArgs.length<>3 + Print "Command line error" + End +EndIf + +Local in:TStream=CreateBankStream( LoadBank( AppArgs[1] ) ),out:TStream + +If AppArgs.length=3 + out=WriteStream( AppArgs[2] ) +Else + out=WriteStream( AppArgs[1] ) +EndIf + +If Not out Throw "Failed to create output stream" + +While Not in.Eof() + + Local line$=in.ReadLine() + + Local t_line$=line + + If line And line[0]=9 + Local i=line.Find( Chr(9),1 ) + If i<>-1 + Local sz + Local op$=line[1..i] + Local args$=line[i+1..] + Select op + Case "db" + op=".byte" + If args[..1]="~q" And args[args.length-3..]="~q,0" + op=".asciz" + args="~q"+args[1..args.length-3]+"~q" + EndIf + Case "dw" + op=".short" + Case "dd" + op=".long" + Case "extrn" + op=".reference" + Case "public" + op=".globl" + Case "align" + op=".align" + Case "file" + If args[..1]="~q" And args[args.length-1..]="~q" + args=args[1..args.length-1] + EndIf + Local r:TStream=ReadStream( args ),n + If Not r Throw "Unable to open file "+args + Local buf:Byte[64] + Repeat + Local n=r.Read( buf,64 ) + If Not n Exit + Local t$="~t.byte~t"+buf[0] + For Local i=1 Until n + t:+","+buf[i] + Next + WriteString out,t + WriteString out,"~n" + Forever + r.Close + op="" + Case "section" + op="."+args + args="" + Default + Local i=args.Find( "," ) + If i=-1 + sz=FixArg( args,op ) + If sz And op="call" args="*"+args + Else + Local arg2$=args[..i] + Local arg1$=args[i+1..] + Local sz1=FixArg( arg1 ) + Local sz2=FixArg( arg2 ) + sz=sz1 + If sz2 sz=sz2 + Select op + Case "lea" + sz=0 + Case "movzx","movsx" + Local s$ + Select sz + Case 1 + s="b" + Case 2 + s="w" + Case 0 + Select arg1 + Case "%al","%bl","%cl","%dl" + s$="b" + Case "%ax","%bx","%cx","%dx","%bp","%sp","%si","%di" + s$="w" + End Select + End Select + op=op[..4]+s+"l" + sz=0 + Case "fdiv","fsub" + If arg1="%st(0)" And arg2[..3]="%st" op=op[..4]+"r" + Case "fdivp","fsubp" + If arg1="%st(0)" And arg2[..3]="%st" op=op[..4]+"rp" + Case "fdivr","fsubr" + If arg1="%st(0)" And arg2[..3]="%st" op=op[..4] + Case "fdivrp","fsubrp" + If arg1="%st(0)" And arg2[..3]="%st" op=op[..4]+"p" + End Select + args=arg1+","+arg2 + EndIf + Local fpsz + If op And op[0]=Asc("f") + Select op + Case .. + "fild","fist","fistp","ficom","ficomp",.. + "fiadd","fisub","fimul","fidiv","fidivr" + Default + fpsz=True + End Select + EndIf + Select sz + Case 1 + op:+"b" + Case 2 + op:+"w" + Case 4 + If fpsz op:+"s" Else op:+"l" + Case 8 + If fpsz op:+"l" Else op:+"q" + End Select + End Select + If op line=Chr(9)+op+Chr(9)+args Else line="" + EndIf + EndIf + + WriteString out,line + WriteString out,"~n" + +Wend + +in.Close + +Catch ex:Object + + WriteStdout "fasm2as failed: "+ex.ToString()+"~n" + + exit_ -1 + +End Try + +End + +Function RegSize( r$ ) + Select r + Case "eax","ebx","ecx","edx","esi","edi","ebp","esp" + Return 4 + End Select +End Function + +Function FixArg( arg$ Var,op$="" ) + + If Not arg.EndsWith( "]" ) + If arg[0]=Asc("_") + If op[0]<>Asc("j") And op<>"call" arg="$"+arg + Else If (arg[0]>=48 And arg[0]<=57) Or arg[0]=Asc("-") + arg="$"+arg + Else + If arg[..2]="st" arg="st("+arg[2..]+")" + arg="%"+arg + EndIf + Return 0 + EndIf + + Local sz + + If arg.StartsWith( "[" ) + arg=arg[1..arg.length-1] + Else If arg.StartsWith( "byte [" ) + arg=arg[6..arg.length-1] + sz=1 + Else If arg.StartsWith( "word [" ) + arg=arg[6..arg.length-1] + sz=2 + Else If arg.StartsWith( "dword [" ) + arg=arg[7..arg.length-1] + sz=4 + Else If arg.StartsWith( "qword [" ) + arg=arg[7..arg.length-1] + sz=8 + Else + Throw "Error" + EndIf + + arg=arg.Replace( "+-","-" ) + arg=arg.Replace( "-","+-" ) + + Local base$,index$,scale$,disp$ + For Local t$=EachIn arg.Split( "+" ) + If t.Contains("*") + If index Throw "Error" + Local bits$[]=t.Split( "*" ) + If bits.length<>2 Throw "Error" + index=bits[0] + scale=bits[1] + Else If RegSize( t ) + If base + If index Throw "Error" + index=t + scale="1" + Else + base=t + EndIf + Else + If disp + disp=(disp+"+"+t).Replace( "+-","-" ) + Else + disp=t + EndIf + EndIf + Next + + If base And index + arg=disp+"(%"+base+",%"+index+","+scale+")" + Else If base + arg=disp+"(%"+base+")" + Else If index + arg=disp+"(,%"+index+","+scale+")" + Else If disp + arg=disp + Else + Throw "Error!" + EndIf + + Return sz +End Function diff --git a/src/makedocs/bbdoc.bmx b/src/makedocs/bbdoc.bmx new file mode 100644 index 0000000..e0947a4 --- /dev/null +++ b/src/makedocs/bbdoc.bmx @@ -0,0 +1,202 @@ + +Strict + +Import "parse.bmx" + +'still pretty ugly - could probably be done in a few lines with Bah.RegEx! + +Type TBBLinkResolver + + Method ResolveLink$( link$ ) Abstract + +End Type + +Private + +'finds a 'span' style tag starting at index i - eg: @bold or @{this is bold} +' +'returns bit after tag, fills in b and e with begin and end of range. +Function FindBBTag$( text$,tag$,i,b Var,e Var ) + Repeat + i=text.Find( tag,i ) + If i=-1 Return + If i=0 Or text[i-1]<=32 Or text[i-1]=Asc(">") Exit + i:+tag.length + Forever + b=i + i:+1 + If i=text.length Return + Local t$ + If text[i]=Asc("{") + i:+1 + While iAsc("}") + i:+1 + Wend + t=text[b+2..i] + If i"+t+"" + text=text[..b]+t+text[e..] + i=b+t.length + Forever +End Function + +Public + +Function BBToHtml2$( text$,doc:TBBLinkResolver ) + Local i + + 'newlines + text=text.Replace( "\~n","
~n" ) + + 'paras + text=text.Replace( "~n~n","~n

~n" ) + + 'tabs + text=text.Replace( "~n~t","~n   " ) + + 'headings + i=0 + Local hl=1 + Repeat + i=text.Find( "~n+",i ) + If i=-1 Exit + + Local i2=text.Find( "~n",i+2 ) + If i2=-1 Exit + + Local q$=text[i+2..i2] + q=""+q+"" + + If hl=1 hl=2 + + text=text[..i]+q+text[i2..] + i:+q.length + Forever + + 'tables + i=0 + Repeat + i=text.Find( "~n[",i ) + If i=-1 Exit + + Local i2=text.Find( "~n]",i+2 ) + If i2=-1 Exit + + Local q$=text[i+2..i2] + + If q.Find( " | " )=-1 'list? + q=q.Replace( "~n*","

  • " ) + q="
      "+q+"
    " + Else + q=q.Replace( "~n*","
  • "+key+""+val+"
    " ) + q=q.Replace( " | ","" ) + q="~n
    "+q+"
    ~n" + EndIf + + text=text[..i]+q+text[i2+2..] + i:+q.length + Forever + + 'quotes + i=0 + Repeat + i=text.Find( "~n{",i ) + If i=-1 Exit + + Local i2=text.Find( "~n}",i+2 ) + If i2=-1 Exit + + Local q$=text[i+2..i2] + + q="
    "+q+"
    " + + text=text[..i]+q+text[i2+2..] + i:+q.length + Forever + + 'links + i=0 + Repeat + Local b,e + Local t$=FindBBTag( text,"#",i,b,e ) + If Not t Exit + + t=doc.ResolveLink( t ) + text=text[..b]+t+Text[e..] + i=b+t.length + Forever + + 'span tags + FormatBBTags text,"@","b" + + FormatBBTags text,"%","i" + + 'escapes + i=0 + Repeat + i=text.Find( "~~",i ) + If i=-1 Or i=text.length-1 Exit + + Local r$=Chr( text[i+1] ) + Select r + Case "<" r="<" + Case ">" r=">" + End Select + + text=text[..i]+r+text[i+2..] + i:+r.length + Forever + + Return text + +End Function + +'bbdoc to html conversion +Function BBToHtml$( text$,doc:TBBLinkResolver ) + + text=text.Replace( "~r~n","~n" ) + + Local out$,i + + 'preformatted code... + Repeat + Local i1=text.Find( "~n{{",i ) + If i1=-1 Exit + + Local i2=text.Find( "~n}}",i+3 ) + If i2=-1 Exit + + out:+BBToHtml2( text[i..i1],doc ) + + out:+"
    "+text[i1+3..i2].Trim()+"
    " + + i=i2+3 + Forever + + out:+BBToHtml2( text[i..],doc ) + + Return out + +End Function + diff --git a/src/makedocs/docnode.bmx b/src/makedocs/docnode.bmx new file mode 100644 index 0000000..30c5a93 --- /dev/null +++ b/src/makedocs/docnode.bmx @@ -0,0 +1,69 @@ + +Strict + +Import BRL.Map + +Type TDocNode + + Field id$ 'eg: BRL.Audio + Field path$ 'eg: Modules/Audio/Audio" + Field kind$ 'eg: "Module", "Function", "Type" etc + + Field proto$ 'eg: Function LoadImage(...) + Field bbdoc$ 'eg: Load an image (shortdesc?) + Field returns$ 'eg: A new image + Field about$ 'eg: blah etc blah (longdesc?) + Field params:TList 'eg: [x - the x coord, y - the y coord] + + Field docDir$ 'eg: ../mod/brl.mod/max2d.mod/doc + Field example$ 'eg: LoadImage.bmx (path) + + Field children:TList=New TList + + Function ForPath:TDocNode( path$ ) + + Return TDocNode( _pathMap.ValueForKey( path ) ) + + End Function + + Function Create:TDocNode( id$,path$,kind$ ) + + Local t:TDocNode=TDocNode( _pathMap.ValueForKey( path ) ) + + If t + If t.kind<>"/" And t.path<>path Throw "ERROR: "+t.kind+" "+kind + If t.path = path Return t + Else + t=New TDocNode + _pathMap.Insert path,t + EndIf + + t.id=id + t.path=path + t.kind=kind + + Local q:TDocNode=t + + Repeat + If path="/" Exit + path=ExtractDir( path ) + Local p:TDocNode=TDocNode( _pathMap.ValueForKey( path ) ) + If p + p.children.AddLast q + Exit + EndIf + p=New TDocNode + p.id=StripDir(path) + p.path=path + p.kind="/" + p.children.AddLast q + _pathMap.Insert path,p + q=p + Forever + + Return t + End Function + + Global _pathMap:TMap=New TMap + +End Type diff --git a/src/makedocs/docstyle.bmx b/src/makedocs/docstyle.bmx new file mode 100644 index 0000000..76a4fa6 --- /dev/null +++ b/src/makedocs/docstyle.bmx @@ -0,0 +1,191 @@ + +Strict + +Import BRL.MaxUtil + +Import "bbdoc.bmx" + +Import "docnode.bmx" + +Global BmxDocDir$=BlitzMaxPath()+"/docs/html" + +Global NodeKinds$[]=[ "/","Module","Type" ] + +Global LeafKinds$[]=[ "Const","Field","Global","Method","Function","Keyword" ] + +Global AllKinds$[]=NodeKinds+LeafKinds + +Type TDocStyle Extends TBBLinkResolver + + Field html$ + Field doc:TDocNode + Field children:TMap + Field docURL$ + Field absDocDir$ 'where output doc goes + Field relRootDir$ 'relative path to root doc dir + + Global commands:TMap=New TMap + + Method NodeIsleaf( node:TDocNode ) + For Local t$=EachIn LeafKinds + If t=node.kind Return True + Next + End Method + + Method FindNode:TDocNode( node:TDocNode,id$ ) + + If node.id.ToLower()=id Return node + + If node.path.Tolower().EndsWith( "/"+id ) Return node + + For Local t:TDocNode=EachIn node.children + Local p:TDocNode=FindNode( t,id ) + If p Return p + Next + End Method + + Method NodeURL$( node:TDocNode ) + If node.kind="Topic" + Return node.path+".html" + Else If NodeIsLeaf( node ) + Return ExtractDir( node.path )+"/index.html#"+node.id + Else If node.path<>"/" + Return node.path+"/index.html" + Else + Return "/index.html" + EndIf + End Method + + Method ResolveLink$( link$ ) + Local id$=link.ToLower() + + Local node:TDocNode=FindNode( doc,id ) + + If Not node + node=FindNode( TDocNode.ForPath( "/" ),id ) + EndIf + + If Not node + Print "Error: Unable to resolve link '"+link+"'" + Return link + EndIf + + Local url$=nodeURL( node ) + + 'optimize links... + If url.StartsWith( docURL+"#" ) + url=url[ docURL.length.. ] + Else If url.StartsWith( doc.path+"/" ) + url="~q"+url[ doc.path.length+1.. ]+"~q" + Else + url="~q"+relRootDir+url+"~q" + EndIf + Return ""+link+"" + End Method + + Method EmitDoc( node:TDocNode ) + + Print "Building: "+node.id + + html="" + doc=node + children=New TMap + docURL=NodeURL( doc ) + absDocDir=BmxDocDir+ExtractDir( docURL ) + relRootDir="" + + Local p$=ExtractDir( docURL ) + While p<>"/" + If relRootDir relRootDir:+"/" + relRootDir:+".." + p=ExtractDir( p ) + Wend + If Not relRootDir relRootDir="." + + CreateDir absDocDir,True + + If doc.docDir CopyDir doc.docDir,absDocDir + + If docURL.EndsWith( "/index.html" ) + Local intro$=absDocDir+"/index.bbdoc" + If FileType( intro )<>FILETYPE_FILE intro$=absDocDir+"/intro.bbdoc" + If FileType( intro )=FILETYPE_FILE + Local t$=LoadText( intro ) + If t.find( "commands.html" )<>-1 + Print "Error: Document contains 'commands.html'" + EndIf + doc.about=t+doc.about + EndIf + EndIf + + For Local t:TDocNode=EachIn doc.children + + Local list:TList=TList( children.ValueForKey( t.kind ) ) + If Not list + list=New TList + children.Insert t.kind,list + EndIf + + list.AddLast t + + 'update commands.txt + Select t.kind + Case "Keyword" + commands.Insert t.id+" : "+t.bbdoc,NodeURL( t ) + Case "Const","Global","Function","Type" ',"Module" + Local i=t.proto.Find( " " ) + If i<>-1 commands.Insert t.proto[i+1..].Trim()+" : "+t.bbdoc,NodeURL( t ) + End Select + Next + + EmitHeader + + For Local t$=EachIn NodeKinds + EmitLinks t + Next + + For Local t$=EachIn LeafKinds + EmitLinks t + Next + + For Local t$=EachIn LeafKinds + EmitDecls t + Next + + EmitFooter + + html=BBToHtml( html,Self ) + + SaveText html,BmxDocDir+docURL + + For Local t$=EachIn NodeKinds + EmitNodes t + Next + + End Method + + Method EmitNodes( kind$ ) + Local list:TList=TList( children.ValueForKey( kind ) ) + If Not list Return + For Local t:TDocNode=EachIn list + EmitDoc t + Next + End Method + + Method Emit( t$ ) + html:+t+"~n" + End Method + + Method ChildList:TList( kind$ ) + Return TList( children.ValueForKey( kind ) ) + End Method + + Method EmitHeader() Abstract + + Method EmitFooter() Abstract + + Method EmitLinks( kind$ ) Abstract + + Method EmitDecls( kind$ ) Abstract + +End Type diff --git a/src/makedocs/fredborgstyle.bmx b/src/makedocs/fredborgstyle.bmx new file mode 100644 index 0000000..8fe86f6 --- /dev/null +++ b/src/makedocs/fredborgstyle.bmx @@ -0,0 +1,128 @@ + +Strict + +Import "docstyle.bmx" + +Type TFredborgStyle Extends TDocStyle + + Method EmitHeader() + + 'emit HTML header + Emit ""+doc.id+"" + Emit "" + Emit "" + + 'emit title bar + Emit "" + Emit "" + + 'emit links to summaries + For Local t$=EachIn allKinds + If t="/" Or Not ChildList( t ) Continue + + Emit "" + + Next + + 'emit link to module source + If doc.kind="Module" + Local t$=ModuleSource( doc.id.ToLower() ),i=t.Find( "/mod/" ) + If i<>-1 + t=relRootDir+"/../.."+t[i..] + Emit "" + EndIf + EndIf + + 'end title bar + Emit "
     "+doc.id+":"+t+"sSource 


    " + + 'emit about + If doc.about Emit doc.about+"

    " + + End Method + + Method EmitFooter() + + 'emit HTML footer + Emit "" + + End Method + + Method EmitLinks( kind$ ) + + Local list:TList=ChildList( kind ) + If Not list Return + + 'emit anchor: _Const, _Function etc... + + If kind="/" + + Emit "" + + For Local t:TDocNode=EachIn list + + Emit "" + + Next + + Emit "
    #{"+t.id+"}
    " + + Else + + Emit "" + Emit "

    "+kind+"s

    " + + Emit "" + + For Local t:TDocNode=EachIn list + + Emit "" + + Next + + Emit "
    #{"+t.id+"}"+t.bbdoc+"
    " + EndIf + + End Method + + Method EmitDecls( kind$ ) + + Local list:TList=ChildList( kind ) + If Not list Return + + Emit "

    "+kind+" reference

    " + + For Local t:TDocNode=EachIn list + + Emit "" + + Emit "

    " + Emit "" + + If t.returns + Emit "" + EndIf + + If t.bbdoc + Emit "" + EndIf + + If t.about + Emit "" + EndIf + + If t.example + Local p$=t.example + Local link$="Example" + Local code$=LoadText( absDocDir+"/"+p ).Trim() + code="~n{{~n"+code+"~n}}~n" + Emit "" + EndIf + + Emit "
    "+t.proto+"
    Returns"+t.returns+"
    Description"+t.bbdoc+"
    Information"+t.about+"
    "+link+""+code+"
    " + + Next + + End Method + +End Type diff --git a/src/makedocs/makedocs.bmx b/src/makedocs/makedocs.bmx new file mode 100644 index 0000000..81a2a10 --- /dev/null +++ b/src/makedocs/makedocs.bmx @@ -0,0 +1,286 @@ + +Rem + +Build new style docs. + +Only builds official docs and brl, maxgui and pub modules. + +Calls 'docmods' first, which builds 3rd party modules. + +End Rem + +Strict + +Framework BRL.Basic + +Import "docnode.bmx" + +Import "fredborgstyle.bmx" + +system_ "~q"+BlitzMaxPath()+"/bin/docmods~q" + +Local style:TDocStyle=New TFredborgStyle + +DeleteDir BmxDocDir,True + +CopyDir BlitzMaxPath()+"/docs/src",BmxDocDir + +Local root:TDocNode=TDocNode.Create( "BlitzMax Help","/","/" ) +root.about=LoadText( BmxDocDir+"/index.html" ) + +DocMods + +DocBBDocs "/" + +style.EmitDoc TDocNode.ForPath( "/" ) + +Local t$ +For Local kv:TKeyValue=EachIn TDocStyle.commands + t:+String( kv.Key() )+"|/docs/html"+String( kv.Value() )+"~n" +Next + +Local p$=BlitzMaxPath()+"/doc/bmxmods/commands.txt" +If FileType( p )=FILETYPE_FILE t:+LoadText( p ) + +SaveText t,BmxDocDir+"/Modules/commands.txt" + +Cleanup BmxDocDir + +'***** + +Function Cleanup( dir$ ) + For Local e$=EachIn LoadDir( dir ) + Local p$=dir+"/"+e + Select FileType( p ) + Case FILETYPE_DIR + Cleanup p + Case FILETYPE_FILE + If ExtractExt( e )="bbdoc" + DeleteFile p + Else If e.ToLower()="commands.html" + DeleteFile p + EndIf + End Select + Next +End Function + +Function DocMods() + + For Local modid$=EachIn EnumModules() + + If Not modid.StartsWith( "brl." ) And Not modid.StartsWith( "pub." ) And Not modid.StartsWith("maxgui.") Continue + + Local p$=ModuleSource( modid ) + Try + docBmxFile p,"" + Catch ex$ + Print "Error:"+ex + End Try + Next + +End Function + +Function DocBBDocs( docPath$ ) + + Local p$=BmxDocDir+docPath + + For Local e$=EachIn LoadDir( p ) + + Local q$=p+"/"+e + + Select FileType( q ) + Case FILETYPE_FILE + Select ExtractExt( e ) + Case "bbdoc" + Local id$=StripExt( e ) + If id="index" Or id="intro" Continue + + Local path$=(docPath+"/"+id).Replace( "//","/" ) + Local node:TDocNode=TDocNode.Create( id,path,"/" ) + + node.about=LoadText( q ) + End Select + Case FILETYPE_DIR + DocBBDocs docPath+"/"+e + End Select + Next + +End Function + +Function docBmxFile( filePath$,docPath$ ) + + If FileType( filePath )<>FILETYPE_FILE + Print "Error: Unable to open '"+filePath+"'" + Return + EndIf + + Local docDir$=ExtractDir( filePath )+"/doc" + If FileType( docDir )<>FILETYPE_DIR docDir="" + + Local inrem,typePath$,section$ + + Local bbdoc$,returns$,about$,keyword$,params:TList + + Local text$=LoadText( filepath ) + + For Local line$=EachIn text.Split( "~n" ) + + line=line.Trim() + Local tline$=line.ToLower() + + Local i + Local id$=ParseIdent( tline,i ) + + If id="end" id:+ParseIdent( tline,i ) + + If it.ToLower() Continue + kind=t + proto=line + id=ParseIdent( line,i ) + Exit + Next + EndIf + + If kind + + Local path$ + + Select kind + Case "Type" + If Not docPath Throw "No doc path" + If typePath Throw "Type path already set" + typePath=docPath + docPath:+"/"+id + path=docPath + Case "Module" + If docPath Throw "Doc path already set" + If bbdoc.FindLast( "/" )=-1 + bbdoc="Other/"+bbdoc + EndIf + docPath="/Modules/"+bbdoc + path=docPath + Local i=bbdoc.FindLast( "/" ) + bbdoc=bbdoc[i+1..] + Default + If Not docPath Throw "No doc path" + path=docPath+"/"+id + End Select + + Local i=proto.Find( ")=" ) + If i<>-1 + proto=proto[..i+1] + If id.StartsWith( "Sort" ) proto:+" )" 'lazy!!!!! + EndIf + i=proto.Find( "=New" ) + If i<>-1 + proto=proto[..i] + EndIf + + Local node:TDocNode=TDocNode.Create( id,path,kind ) + + node.proto=proto + node.bbdoc=bbdoc + node.returns=returns + node.about=about + node.params=params + + If kind="Module" node.docDir=docDir + + Local tmpExampleFilePath$ = CasedFileName(docDir+"/"+id+".bmx") + If docDir And FileType( tmpExampleFilePath )=FILETYPE_FILE + node.example=StripDir(tmpExampleFilePath) + EndIf + + EndIf + + bbdoc="" + + EndIf + Next + +End Function diff --git a/src/makedocs/parse.bmx b/src/makedocs/parse.bmx new file mode 100644 index 0000000..e76f500 --- /dev/null +++ b/src/makedocs/parse.bmx @@ -0,0 +1,61 @@ + +Strict + +Function IsAlphaChar( char ) + Return (char>=Asc("A") And char<=Asc("Z")) Or (char>=Asc("a") And char<=Asc("z")) Or (char=Asc("_")) +End Function + +Function IsDecChar( char ) + Return (char>=Asc("0") And char<=Asc("9")) +End Function + +Function IsIdentChar( char ) + Return IsAlphaChar( char ) Or IsDecChar( char ) +End Function + +Function IsHexChar( char ) + Return IsDecChar( char ) Or (char>=Asc("A") And char<=Asc("F")) Or (char>=Asc("a") And char<=Asc("f")) +End Function + +Function IsBinChar( char ) + Return (char>=Asc("0") And char<=Asc("1")) +End Function + +Function IsPunctChar( char ) + Select char + Case Asc("."),Asc(","),Asc(";"),Asc(":" ),Asc("!"),Asc("?") Return True + End Select +End Function + +Function ParseWS$( t$,i Var ) + Local i0=i + While iAsc("~q") Return + i:+1 + Local i0=i + While iAsc("~q" ) + i:+1 + Wend + Local q$=t[i0..i] + If i + + + + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + bmx + + CFBundleTypeIconFile + MaxIDE.icns + CFBundleTypeRole + Editor + LSIsAppleDefaultForType + + + + CFBundleExecutable + MaxIDE + CFBundleIconFile + MaxIDE.icns + CFBundlePackageType + APPL + + diff --git a/src/maxide/bmxlogo.png b/src/maxide/bmxlogo.png new file mode 100644 index 0000000..16dcc44 Binary files /dev/null and b/src/maxide/bmxlogo.png differ diff --git a/src/maxide/default.language.ini b/src/maxide/default.language.ini new file mode 100644 index 0000000..d521702 --- /dev/null +++ b/src/maxide/default.language.ini @@ -0,0 +1,307 @@ +[LanguageDefinition] + +LanguageID = English (English) +LanguageVersion = v1.07 +LanguageAuthor = BRL + +; Toolbar Tips +tb_new = "New" +tb_open = "Open" +tb_close = "Close" +tb_save = "Save" +tb_cut = "Cut" +tb_copy = "Copy" +tb_paste = "Paste" +tb_find = "Find" +tb_build = "Build" +tb_buildrun = "Build and Run" +tb_step = "Step" +tb_stepin = "Step In" +tb_stepout = "Step Out" +tb_stop = "Stop" +tb_home = "Home" +tb_back = "Back" +tb_forward = "Forward" +tb_continue = "Continue" + +; Tabs +tab_help = "Help" +tab_output = "Output" +tab_locked:%1 = "build:%1" + +; Navbar Tabs +navtab_home = "Home" +navtab_code = "Code" +navtab_debug = "Debug" + +; Navigation Tree Nodes +navnode_help = "Help" +navnode_projects = "Projects" +navnode_addproject = "Add Project" +navnode_moduleindex = "Index" +navnode_thirdpartymods = "Third party modules" + +; Misc Buttons +btn_ok = "OK" +btn_cancel = "Cancel" +btn_close = "Close" + +; Find Requester +find_window_title = "Find" +find_label_find = "Find" +find_btn_find = "Find" +find_notification_cannotfind = "Could not find '%1'." + +; Find & Replace Requester +replace_window_title = "Find and Replace" +replace_label_find = "Find" +replace_label_replacewith = "Replace With" +replace_btn_replace = "Replace" +replace_btn_replaceall = "Replace All" +replace_btn_findnext = "Find Next" + +; About Requester +about_window_title = "About MaxIDE" +about_label_bccver = "BCC Version" +about_label_bmxpath = "BlitzMax Path" +about_label_mingwpath = "MinGW Path" +about_label_fasmver = "FASM Version" +about_label_gccver = "GCC Version" +about_label_gplusplusver = "G++ Version" +about_error_unavailable = "Unavailable" +about_error_notapplicable = "n/a" + +; Goto Requester +goto_window_title = "Goto Line" +goto_label_linenum = "Line Number" +goto_btn_goto = "Goto" + +; Command Line Requester +cmdline_window_title = "Program Command Line" +cmdline_label_cmdline = "Program command line" + +; Progress Requester +progress_window_title = "Progress Requester" + +; Options Requester +options_window_title = "Options" +options_optionstab = "Options" +options_editortab = "Editor" +options_toolstab = "Tools" + +options_options_label_language = "Language" +options_options_btn_showtoolbar = "Show Toolbar" +options_options_btn_autorestore = "Open Files at Startup" +options_options_btn_autocaps = "Auto Capitalize" +options_options_btn_syntaxhighlight = "Syntax Highlighting" +options_options_btn_bracketmatching = "Enable .bmx Bracket Matching" +options_options_btn_autobackup = "Auto Backup" +options_options_btn_autoindent = "Auto Indent" +options_options_btn_autohideoutput = "Hide Output When Process Completes" +options_options_btn_useexternalbrowser = "Use External Help Browser" +options_options_btn_osshortcuts = "Use OS Specific Shortcut Keys" +options_options_btn_sortcodeviewnodes = "Sort Nodes in Code View" + +options_editor_label_background = "Background" +options_editor_itemlabel_tabsize = "Tab Size:" +options_editor_label_plaintext = "Plain Text" +options_editor_label_remarks = "Remarks" +options_editor_label_strings = "Strings" +options_editor_label_keywords = "Keywords" +options_editor_label_numbers = "Numbers" +options_editor_label_matchings = "Matchings" + +options_tools_label_output = "Output" +options_tools_label_navbar = "Navbar" + +options_font_desc_user = "User Defined Font" +options_font_desc_guidefault = "GUI Default Font" +options_font_desc_monospaced = "Monospaced Font" +options_font_desc_sansserif = "Sans Serif Font" +options_font_desc_serif = "Serif Font" +options_font_desc_script = "Script Font" + +; Text Style Control +txtstyle_underline = "Underline" +txtstyle_normal = "Normal" +txtstyle_bold = "Bold" +txtstyle_italic = "Italic" +txtstyle_bolditalic = "Bold + Italic" + +; Project Manager +projman_window_title = "Project Manager" +projman_btn_addproj = "Add Project" +projman_btn_delproj = "Remove Project" +projman_btn_moveup = "Move Up" +projman_btn_movedn = "Move Down" +projman_btn_properties = "Properties" + +; Project Requester +project_window_title = "Project Properties" +project_group_details = "Project Details" +project_label_name = "Name" +project_defaultname = "New Project" +project_label_path = "Path" +project_group_svn = "Subversion Control" +project_label_url = "URL" +project_label_username = "Username" +project_label_password = "Password" +project_btn_checkout = "Check Out Project" +project_btn_update = "Update Project" +project_btn_commit = "Commit Project" +project_requestfolder_title = "Select the project folder" + +; Syncmods Requester +syncmods_window_title = "Synchronize Modules" +syncmods_label_username = "Username" +syncmods_label_password = "Password" +syncmods_label_proxyserver = "Proxy Server" +syncmods_process_label = "Synchronize Modules" +syncmods_btn_sync = "Sync" + +; Search Requester +search_window_title = "Find In Files" +search_label_find = "Find" +search_label_filetypes = "File Types" +search_type_bmaxfiles = "BlitzMax Files" +search_type_codefiles = "Code Files" +search_type_allfiles = "All Files (Warning: Includes Binary Files)" +search_label_searchpath = "Search Path" +search_btn_searchsubfolders = "Search sub-directories" +search_btn_startsearch = "Search" +search_btn_stopsearch = "Stop Search" +search_requestfolder_title = "Choose a folder to search..." +search_msg_complete = "Search complete! Found %1 instance(s)!" +search_msg_searchingdir = "Searching: %1" +search_error_pathnotfound = "The specified path does not exist!" +search_error_pathisfile = "The path entered is for a file, please enter the path of a directory." +search_error_nosearchstring = "You must enter a search string to find!" +search_safetynotification = "There have been %1 instances found.\n\nWould you like to continue?" + +; Misc Notifications / Requesters +request_restart = "MaxIDE would like to restart." +request_closeall = "MaxIDE needs to close all documents before continuing." +request_openfile = "Open File" +request_saveas_title = "Save As" +request_importbb_title = "Import .bb file" +request_savechanges = "Save changes to %1?" +notify_demo_featureunavailable = "This feature is unavailable in the demo version of BlitzMax." + +; SVN Messages +svn_notification_nodehostnotfound = "Node host not found." +svn_notification_nodeprojectnotfound = "Node project not found." +svn_msg_updating = "Updating %1" +svn_msg_committing = "Committing %1" +svn_msg_checkingout = "Checking out %1 to %2" + +; Output Messages +output_error_compileerror = "Compile Error\n\n%1" +output_notification_stillbusy = "Current process still busy %1." +output_notification_processfailure = "Process failure with %1." +output_notification_processfailure = "Process failed to start %1." +output_msg_rebuildingdocs = "Rebuilding documentation..." +output_msg_buildingmods = "Building Modules" +output_msg_converting = "Converting %1" +output_msg_processcomplete = "Process complete" +output_msg_processterminated = "Process terminated" +output_msg_debugfailure = "Process debug failure. Cannot write:\n%1" + +; Loading Errors +loaderror_failed = "Failed to open '%1'." +loaderror_docsnotfound = "Documentation not found.\n\nWould you like to rebuild documentation now?" + +; Misc +status_line_char = "Line: %1 Char: %2" +msg_loading = "Loading %1" +msg_highlightingcode = "Highlighting Code" + +; Menus +menu_file = "&File" +menu_file_new = "&New" +menu_file_open = "&Open..." +menu_file_open_recent = "Open &Recent" +menu_file_closetab = "&Close Tab" +menu_file_closealltabs = "Close All Tabs" +menu_file_closeothertabs = "Close Other Tabs" +menu_file_save = "&Save" +menu_file_saveas = "Save &As" +menu_file_saveall = "Save A&ll" +menu_file_nexttab = "&Next Tab" +menu_file_prevtab = "&Previous Tab" +menu_file_importbb = "Import BB Project..." +menu_file_ideoptions = "IDE Options" +menu_file_projectmanager = "&Project Manager" +menu_file_print = "Print" +menu_file_exit = "Exit" + +menu_edit = "&Edit" +menu_edit_undo = "&Undo" +menu_edit_redo = "&Redo" +menu_edit_cut = "Cu&t" +menu_edit_copy = "&Copy" +menu_edit_paste = "&Paste" +menu_edit_selectall = "Select &All" +menu_edit_blockindent = "Block Indent" +menu_edit_blockoutdent = "Block Outdent" +menu_edit_find = "&Find..." +menu_edit_findnext = "Find Next" +menu_edit_replace = "&Replace..." +menu_edit_gotoline = "&Goto Line..." +menu_edit_findinfiles = "Find in F&iles" + +menu_program = "&Program" +menu_program_build = "&Build" +menu_program_buildandrun = "Build and &Run" +menu_program_commandline = "Command &Line" +menu_program_step = "&Step" +menu_program_stepin = "Step &In" +menu_program_stepout = "Step &Out" +menu_program_terminate = "&Terminate" +menu_program_buildoptions = "Build Options" +menu_program_buildoptions_quick = "Quick Build" +menu_program_buildoptions_debug = "Debug Build" +menu_program_buildoptions_threaded = "Threaded Build" +menu_program_buildoptions_guiapp = "Build GUI App" +menu_program_lockbuildfile = "&Lock Build File" +menu_program_unlockbuildfile = "&Unlock Build File" +menu_program_syncmods = "Synchronize Modules..." +menu_program_buildmods = "Build &Modules" +menu_program_rebuildallmods = "Rebuild &All Modules" +menu_program_rebuilddocs = "&Rebuild Documentation" + +menu_help = "&Help" +menu_help_home = "&Home" +menu_help_back = "&Back" +menu_help_forward = "&Forward" +menu_help_quickhelp = "&Quick Help" +menu_help_aboutmaxide = "&About MaxIDE" + +; Popup Menus +popup_edit = "Edit" +popup_edit_quickhelp = "Quick Help" +popup_edit_cut = "Cut" +popup_edit_copy = "Copy" +popup_edit_paste = "Paste" +popup_edit_selectall = "Select All" +popup_edit_blockindent = "Block Indent" +popup_edit_blockoutdent = "Block Outdent" +popup_edit_find = "Find" +popup_edit_findnext = "Find Next" +popup_edit_replace = "Replace" +popup_edit_goto = "Goto Line" + +popup_output = "Edit" +popup_output_cut = "Cut" +popup_output_copy = "Copy" +popup_output_paste = "Paste" +popup_output_stop = "Stop" + +popup_nav_proj = "Proj" +popup_nav_proj_refresh = "Refresh" +popup_nav_proj_clean = "Clean" +popup_nav_proj_findinfiles = "Find in Files" +popup_nav_proj_explore = "Explore" +popup_nav_proj_shell = "Shell" +popup_nav_proj_svnupdate = "Update Version" +popup_nav_proj_svncommit = "Commit Version" +popup_nav_proj_properties = "Properties" \ No newline at end of file diff --git a/src/maxide/makeicons/Back.png b/src/maxide/makeicons/Back.png new file mode 100644 index 0000000..c70a451 Binary files /dev/null and b/src/maxide/makeicons/Back.png differ diff --git a/src/maxide/makeicons/Build-Run.png b/src/maxide/makeicons/Build-Run.png new file mode 100644 index 0000000..f03f3ef Binary files /dev/null and b/src/maxide/makeicons/Build-Run.png differ diff --git a/src/maxide/makeicons/Build.png b/src/maxide/makeicons/Build.png new file mode 100644 index 0000000..f9b8d2f Binary files /dev/null and b/src/maxide/makeicons/Build.png differ diff --git a/src/maxide/makeicons/Close.png b/src/maxide/makeicons/Close.png new file mode 100644 index 0000000..4755807 Binary files /dev/null and b/src/maxide/makeicons/Close.png differ diff --git a/src/maxide/makeicons/Copy.png b/src/maxide/makeicons/Copy.png new file mode 100644 index 0000000..8d7751b Binary files /dev/null and b/src/maxide/makeicons/Copy.png differ diff --git a/src/maxide/makeicons/Cut.png b/src/maxide/makeicons/Cut.png new file mode 100644 index 0000000..8e41a70 Binary files /dev/null and b/src/maxide/makeicons/Cut.png differ diff --git a/src/maxide/makeicons/Find.png b/src/maxide/makeicons/Find.png new file mode 100644 index 0000000..ca4b46f Binary files /dev/null and b/src/maxide/makeicons/Find.png differ diff --git a/src/maxide/makeicons/Forward.png b/src/maxide/makeicons/Forward.png new file mode 100644 index 0000000..8a53374 Binary files /dev/null and b/src/maxide/makeicons/Forward.png differ diff --git a/src/maxide/makeicons/Go.png b/src/maxide/makeicons/Go.png new file mode 100644 index 0000000..5b6b736 Binary files /dev/null and b/src/maxide/makeicons/Go.png differ diff --git a/src/maxide/makeicons/Home.png b/src/maxide/makeicons/Home.png new file mode 100644 index 0000000..7a8b526 Binary files /dev/null and b/src/maxide/makeicons/Home.png differ diff --git a/src/maxide/makeicons/New.png b/src/maxide/makeicons/New.png new file mode 100644 index 0000000..61ad414 Binary files /dev/null and b/src/maxide/makeicons/New.png differ diff --git a/src/maxide/makeicons/Open.png b/src/maxide/makeicons/Open.png new file mode 100644 index 0000000..cbb468c Binary files /dev/null and b/src/maxide/makeicons/Open.png differ diff --git a/src/maxide/makeicons/Paste.png b/src/maxide/makeicons/Paste.png new file mode 100644 index 0000000..56eebd1 Binary files /dev/null and b/src/maxide/makeicons/Paste.png differ diff --git a/src/maxide/makeicons/Save.png b/src/maxide/makeicons/Save.png new file mode 100644 index 0000000..2e45ce2 Binary files /dev/null and b/src/maxide/makeicons/Save.png differ diff --git a/src/maxide/makeicons/Step-In.png b/src/maxide/makeicons/Step-In.png new file mode 100644 index 0000000..d5f8e46 Binary files /dev/null and b/src/maxide/makeicons/Step-In.png differ diff --git a/src/maxide/makeicons/Step-Out.png b/src/maxide/makeicons/Step-Out.png new file mode 100644 index 0000000..87d5c3b Binary files /dev/null and b/src/maxide/makeicons/Step-Out.png differ diff --git a/src/maxide/makeicons/Step.png b/src/maxide/makeicons/Step.png new file mode 100644 index 0000000..6eae3d0 Binary files /dev/null and b/src/maxide/makeicons/Step.png differ diff --git a/src/maxide/makeicons/Stop.png b/src/maxide/makeicons/Stop.png new file mode 100644 index 0000000..3f38a83 Binary files /dev/null and b/src/maxide/makeicons/Stop.png differ diff --git a/src/maxide/makeicons/makeicons.bmx b/src/maxide/makeicons/makeicons.bmx new file mode 100644 index 0000000..c8b68e8 --- /dev/null +++ b/src/maxide/makeicons/makeicons.bmx @@ -0,0 +1,62 @@ + +Strict + +Local n +Repeat + Local t$ + ReadData t$ + If Not t Exit + n:+1 +Forever + +Local sz=24 + +Local p:TPixmap + +RestoreData Here +Local x=0 + +Repeat + Local t$ + ReadData t + If Not t Exit + + If t<>" " + Local q:TPixmap=LoadPixmap( t+".png" ) + If Not p + Local rgb=0'q.readpixel( 0,0 ) + p=TPixmap.Create( n*sz,sz,PF_RGBA8888 ) + For Local y=0 Until sz + For Local x=0 Until n*sz + p.WritePixel x,y,rgb + Next + Next + EndIf + If q.width>sz Or q.height>sz + q=ResizePixmap( q,sz,sz ) + EndIf + Local cx=(sz-q.width)/2 + Local cy=(sz-q.height)/2 + p.paste q,x+cx,cy + EndIf + x:+sz +Forever + +SavePixmapPNG p,"../toolbar.png" + +Local i:TImage=LoadImage(p) + +Graphics 640,480,0 +DrawPixmap p,0,0 + +DrawImage i,0,100 +Flip +WaitKey + +#Here +DefData "New","Open","Close","Save"," " +DefData "Cut","Copy","Paste","Find"," " +DefData "Build","Build-Run","Step","Step-In","Step-Out","Stop"," " +DefData "Home","Back","Forward" +DefData "Go","" + diff --git a/src/maxide/maxicons.o b/src/maxide/maxicons.o new file mode 100644 index 0000000..dc11fcf Binary files /dev/null and b/src/maxide/maxicons.o differ diff --git a/src/maxide/maxide.bmx b/src/maxide/maxide.bmx new file mode 100644 index 0000000..ebf04df --- /dev/null +++ b/src/maxide/maxide.bmx @@ -0,0 +1,6560 @@ + +' maxide.bmx - blitzmax native integrated development environment + +' by simonarmstrong@blitzbasic.com + +' released under the Blitz Shared Source Code License 2005 +' released into the public domain 2006 + +' requires MaxGui modules to run + +Strict + +Framework MaxGUI.Drivers +Import MaxGUI.ProxyGadgets + +?Win32 +Import "maxicons.o" +? + +'Import bah.gtkmaxgui +'Import bah.gtkwebgtkhtml +'Import bah.gtkwebmozilla + +Import brl.eventqueue +Import brl.standardio +Import brl.filesystem +Import brl.system +Import brl.ramstream +Import pub.freeprocess +Import brl.pngloader +Import brl.timer +Import brl.maxutil + +Incbin "bmxlogo.png" +Incbin "toolbar.png" +Incbin "splash.png" +Incbin "default.language.ini" + +Const DEFAULT_LANGUAGEPATH$ = "incbin::default.language.ini" + +?Linux +Incbin "window_icon.png" +? + +AppTitle = "MaxIDE" + +Const IDE_VERSION$="1.43" +Const TIMER_FREQUENCY=15 + +?Win32 +Extern + Global _bbusew 'secret 'NT' flag +End Extern + +If Not _bbusew + Notify.. + "This program is not compatible with Windows 95/98/ME.~n~n"+.. + "Please visit www.blitzbasic.com to download a compatible version.",True + End +EndIf +? + +Global BCC_VERSION$="{unknown}" 'not valid until codeplay opened + +Const EOL$="~n" + +Const ABOUT$=.. +"{bcc_version} - Copyright Blitz Research Ltd.~n~n"+.. +"Please visit www.blitzbasic.com for all your Blitz related needs!" + +Const ABOUTDEMO$=.. +"This demo features both the core BlitzMax package and optional MaxGUI module.~n~n"+.. +"Please note that the MaxGUI module must be purchased separately." + +Const FileTypes$="bmx,bbdoc,txt,ini,doc,plist,bb,cpp,c,cc,m,cxx,s,glsl,hlsl,lua,py,h,hpp,html,htm,css,js,bat,mm,as,java,bbx,cx" +Const FileTypeFilters$="Code Files:"+FileTypes$+";All Files:*" + +Const HOMEPAGE$="/docs/html/index.html" + +?MacOS +Global SVNCMD$="/usr/local/bin/svn" +Const LABELOFFSET=2 +?Win32 +Global SVNCMD$="svn" +Const LABELOFFSET=4 +?Linux +Global SVNCMD$="/usr/bin/svn" +Const LABELOFFSET=0 +? + +Const MENUNEW=1 +Const MENUOPEN=2 +Const MENUCLOSE=3 +Const MENUSAVE=4 +Const MENUSAVEAS=5 +Const MENUSAVEALL=6 +Const MENUPRINT=7 +Const MENUQUIT=8 + +Const MENUUNDO=9 +Const MENUREDO=10 +Const MENUCUT=11 +Const MENUCOPY=12 +Const MENUPASTE=13 +Const MENUSELECTALL=14 +Const MENUGOTO=15 +Const MENUINDENT=16 +Const MENUOUTDENT=17 +Const MENUFIND=18 +Const MENUFINDNEXT=19 +Const MENUREPLACE=20 +Const MENUNEXT=21 +Const MENUPREV=22 +Const MENUBUILD=23 +Const MENURUN=24 + +Const MENUSTEP=25 +Const MENUSTEPIN=26 +Const MENUSTEPOUT=27 +Const MENUSTOP=28 + +Const MENULOCKBUILD=29 +Const MENUUNLOCKBUILD=30 +Const MENUBUILDMODULES=31 +Const MENUBUILDALLMODULES=32 + +Const MENUQUICKENABLED=33 +Const MENUDEBUGENABLED=34 +Const MENUGUIENABLED=35 + +Const MENUCOMMANDLINE=36 +'Const MENUSYNCMODS=37 +Const MENUIMPORTBB=38 +Const MENUFINDINFILES=39 +Const MENUPROJECTMANAGER=40 +Const MENUSHOWCONSOLE=41 +Const MENUOPTIONS=42 + +Const MENUHOME=43 +Const MENUBACK=44 +Const MENUFORWARD=45 +Const MENUQUICKHELP=46 +Const MENUABOUT=47 + +Const MENUNEWVIEW=48 +Const MENUDOCMODS=49 + +Const MENUTRIGGERDOCMODS=50 +Const MENUTRIGGERSYNCDOCS=51 + +Const MENUCLOSEALL=53 + +Const MENUREFRESH=54 +Const MENUBROWSE=55 +Const MENUSHELL=56 +Const MENUPROPS=57 + +Const MENUUPDATE=58 +Const MENUCOMMIT=59 + +Const MENUCLOSEOTHERS=60 + +Const MENUTHREADEDENABLED=61 + +Const MENURECENT=256 + +Const TB_NEW=0 +Const TB_OPEN=1 +Const TB_CLOSE=2 +Const TB_SAVE=3 +Const TB_CUT=5 +Const TB_COPY=6 +Const TB_PASTE=7 +Const TB_FIND=8 +Const TB_BUILD=10 +Const TB_BUILDRUN=11 +Const TB_STEP=12 +Const TB_STEPIN=13 +Const TB_STEPOUT=14 +Const TB_STOP=15 +Const TB_HOME=17 +Const TB_BACK=18 +Const TB_FORWARDS=19 +Const TB_CONTINUE=20 + +Const TAB$=Chr(9) +Const QUOTES$=Chr(34) + +Global TEMPCOUNT +Global is_demo +Global codeplay:TCodePlay + +Function CheckDemo() + If Not is_demo Return 1 + Notify LocalizeString("{{notify_demo_featureunavailable}}") + Return 0 +End Function + +Global defaultLanguage:TMaxGUILanguage = LoadLanguage( DEFAULT_LANGUAGEPATH ) + +SetLocalizationLanguage( defaultLanguage ) +SetLocalizationMode( LOCALIZATION_ON|LOCALIZATION_OVERRIDE ) + +codeplay=New TCodePlay +codeplay.Initialize + +While codeplay.running + codeplay.poll +Wend + +End + +Function Quote$(a$) 'add quotes to arg if spaces found + Local p + If Not a.length Return + If a[0]=34 Return a 'already quoted + p=a.find(" ") + If p=-1 Return a 'no spaces + Return Chr(34)+a+Chr(34) +End Function + +Type TToken + Field token$ + Field help$ + Field ref$ + Method Create:TToken(t$,h$,r$) + token=t + help=h + ref=r + Return Self + End Method +End Type + +Type TQuickHelp + Field map:TMap=New TMap 'key=lower(token) value=token:TToken + + Method AddCommand:TQuickHelp(t$,l$,a$) + map.Insert t.ToLower(),New TToken.Create(t$,l$,a$) + End Method + + Method Token$(cmd$) + Local t:TToken = TToken(map.ValueForKey(cmd.toLower())) + If t Return t.token + End Method + + Method Help$(cmd$) + Local t:TToken = TToken(map.ValueForKey(cmd.toLower())) + If t Return t.help + End Method + + Method Link$(cmd$) + Local t:TToken = TToken(map.ValueForKey(cmd.toLower())) + If t Return t.ref + End Method + + Function LoadCommandsTxt:TQuickHelp(bmxpath$) + Local text$ + Local qh:TQuickHelp + Local i:Int,c,p,q + Local token$,help$,anchor$ + Try + text=CacheAndLoadText(bmxpath+"/docs/html/Modules/commands.txt") + Catch exception:Object + Return Null + EndTry + If Not text Return Null + qh=New TQuickHelp + For Local l$ = EachIn text.Split("~n") + For i=0 Until l.length + c=l[i] + If c=Asc("_") Continue + If c>=Asc("0") And c<=Asc("9") Continue + If c>=Asc("a") And c<=Asc("z") Continue + If c>=Asc("A") And c<=Asc("Z") Continue + Exit + Next + token$=l[..i] + help$="" + anchor$="" + q=l.findlast("|") + If q>=0 + help=l[..q] + anchor=l[q+1..] + EndIf + qh.AddCommand token,help,anchor + Next + Return qh + End Function +End Type + +Const TOOLSHOW=1 +Const TOOLREFRESH=2 +Const TOOLNEW=3 +Const TOOLOPEN=4 +Const TOOLCLOSE=5 +Const TOOLSAVE=6 +Const TOOLHELP=7 +Const TOOLUNDO=8 +Const TOOLREDO=9 +Const TOOLCUT=10 +Const TOOLCOPY=11 +Const TOOLPASTE=12 +Const TOOLQUICKSAVE=13 +Const TOOLSAVEAS=14 +Const TOOLGOTO=15 +Const TOOLFIND=16 +Const TOOLFINDNEXT=17 +Const TOOLREPLACE=18 +Const TOOLBUILD=19 +Const TOOLRUN=20 +Const TOOLLOCK=21 +Const TOOLUNLOCK=22 +Const TOOLSELECT=23 +Const TOOLSELECTALL=24 +Const TOOLINDENT=25 +Const TOOLOUTDENT=26 +Const TOOLACTIVATE=27 +Const TOOLNAVIGATE=28 +Const TOOLNEWVIEW=29 +Const TOOLMENU=30 +Const TOOLPRINT=31 +Const TOOLERROR=32 +Const TOOLOUTPUT=32 + +Type TTool + Method Invoke(command,argument:Object=Null) + End Method +End Type + +Type TRequester + + Const STYLE_OK% = 1, STYLE_CANCEL% = 2 + Const STYLE_DIVIDER% = 4, STYLE_STATUS% = 8 + Const STYLE_RESIZABLE% = 16, STYLE_STDBORDER% = 32 + Const STYLE_MODAL% = 64 + + Field host:TCodePlay + Field window:TGadget,ok:TGadget,cancel:TGadget,divider:TGadget + Field centered, modal + + Method initrequester(owner:TCodeplay,label$,w=260,h=60,flags=STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER,oktext$="{{btn_ok}}") + + host=owner + If (flags&STYLE_MODAL) Then flags:|STYLE_STDBORDER + + If (flags & (STYLE_CANCEL|STYLE_OK)) Then h:+32;If (flags&STYLE_DIVIDER) Then h:+12 + + Local windowflags% = WINDOW_TITLEBAR|WINDOW_HIDDEN|WINDOW_CLIENTCOORDS + If (flags & STYLE_STATUS) Then windowflags:|WINDOW_STATUS + If (flags & STYLE_RESIZABLE) Then windowflags:|WINDOW_RESIZABLE + If Not (flags & STYLE_STDBORDER) Then windowflags:|WINDOW_TOOL + + window=CreateWindow(label,0,0,w,h,host.window,windowflags) + + If (flags & STYLE_RESIZABLE) Then + If (flags & STYLE_STDBORDER) Then SetMaxWindowSize(window,ClientWidth(Desktop()),ClientHeight(Desktop())) + SetMinWindowSize(window,w,h) + EndIf + + If (flags & STYLE_OK) Then + + ok=CreateButton(oktext,ClientWidth(window)-101,ClientHeight(window)-32,95,26,window,BUTTON_OK) + SetGadgetLayout(ok,EDGE_CENTERED,EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED) + + If (flags & STYLE_CANCEL) Then + cancel=CreateButton("{{btn_cancel}}",6,ClientHeight(window)-32,95,26,window,BUTTON_CANCEL) + SetGadgetLayout(cancel,EDGE_ALIGNED,EDGE_CENTERED,EDGE_CENTERED,EDGE_ALIGNED) + EndIf + + Else + If (flags & STYLE_CANCEL) Then + cancel=CreateButton("{{btn_close}}",ClientWidth(window)-101,ClientHeight(window)-32,95,26,window,BUTTON_CANCEL) + SetGadgetLayout(cancel,EDGE_CENTERED,EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED) + EndIf + EndIf + + If (flags & STYLE_DIVIDER) And (flags & (STYLE_OK|STYLE_CANCEL)) Then + divider = CreateLabel( "", 6, ClientHeight(window)-42, ClientWidth(window)-12, 4, window, LABEL_SEPARATOR ) + SetGadgetLayout(divider,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED) + EndIf + + If (flags & STYLE_MODAL) Then modal = True Else modal = False + + End Method + + Method Show() + Local x,y,w,h,win:TGadget + If Not centered + win=host.window + w=GadgetWidth(window) + h=GadgetHeight(window) + x=GadgetX(win)+(GadgetWidth(win)-w)/2 + y=GadgetY(win)+(GadgetHeight(win)-h)/2 + SetGadgetShape window,x,y,w,h + centered=True + EndIf + host.HookRequester Self + ShowGadget window + ActivateGadget window + PollSystem + End Method + + Method Hide() + EnableGadget host.window + HideGadget window + host.UnhookRequester Self + host.SelectPanel host.currentpanel + End Method + Method IsModal() + Return modal + EndMethod + Method Poll() + End Method +End Type + +Rem +Type TProgressRequester Extends TRequester + Field message$,value + Field showing + Field label:TGadget + Field progbar:TGadget + + Method Show() 'returns false if cancelled + showing=True + Super.Show + End Method + + Method Hide() + showing=False + Super.Hide() + End Method + + Method Open(title$) + SetGadgetText window,title + Show + End Method + + Method Update(msg$,val) + If msg$<>message + message=msg + If label FreeGadget label + label=CreateLabel(message,8,8,260,20,window) + EndIf + If showing And (val&$fc)<>(value&$fc) 'only update every 4 percent + UpdateProgBar( progbar,val/100.0 ) + PollSystem + EndIf + value=val + End Method + + Function Create:TProgressRequester(host:TCodePlay) + Local progress:TProgressRequester + progress=New TProgressRequester + progress.initrequester(host,"{{progress_window_title}}",280,128,STYLE_CANCEL) + progress.progbar=CreateProgBar( 8,32,260,20,progress.window ) + Return progress + End Function +End Type +EndRem + +Type TPanelRequester Extends TRequester + Field tabber:TGadget + Field panels:TGadget[] + Field index + + Method InitPanelRequester(owner:TCodeplay,label$,w=280,h=128) + InitRequester owner,label,w,h,STYLE_OK|STYLE_CANCEL|STYLE_STDBORDER|STYLE_MODAL + tabber=CreateTabber(6,6,w-12,h-12,window) + SetGadgetLayout tabber,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED + End Method + + Method SetPanelIndex(i) + HideGadget panels[index] + index=i + ShowGadget panels[index] + SelectGadgetItem tabber,index + End Method + + Method SetPanel(panel:TGadget) + Local i + For Local p:TGadget = EachIn panels + If p=panel SetPanelIndex i;Exit + i:+1 + Next + End Method + + Method AddPanel:TGadget(name$) + Local panel:TGadget + panel=CreatePanel(0,0,ClientWidth(tabber),ClientHeight(tabber),tabber) + SetGadgetLayout panel,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED + HideGadget panel + AddGadgetItem tabber,name,GADGETITEM_LOCALIZED + panels=panels[..panels.length+1] + panels[panels.length-1]=panel + Return panel + End Method + + Method RemovePanel(panel) + End Method + +End Type + +Type TAboutRequester Extends TRequester + + Global pixLogo:TPixmap + + Field pnlLogo:TGadget, lblTitle:TGadget, lblSubtitle:TGadget + Field lblLeftAligned:TGadget[], lblRightAligned:TGadget[] + Field hypBlitz:TGadget + + Method PopulateText() + + Local strHeadings$[], strValues$[] + + strHeadings:+["{{about_label_bccver}}:"] + strValues:+[BCC_VERSION] + + strHeadings:+[""] + strValues:+[""] + + strHeadings:+["{{about_label_bmxpath}}:"] + ?Win32 + strValues:+[BlitzMaxPath().Replace("/","\")] + ?Not Win32 + strValues:+[BlitzMaxPath()] + ? + + ?Win32 + strHeadings:+["{{about_label_mingwpath}}:"] + If getenv_("MINGW") Then + strValues:+[getenv_("MINGW")] + Else + strValues:+[LocalizeString("{{about_error_unavailable}}")] + EndIf + ? + + strHeadings:+[""] + strValues:+[""] + + ?Not MacOS + strHeadings:+["{{about_label_fasmver}}:"] + strValues:+[GetFASM()] + ? + + strHeadings:+["{{about_label_gccver}}:"] + strValues:+[GetGCC()] + + strHeadings:+["{{about_label_gplusplusver}}:"] + strValues:+[GetGpp()] + + PopulateColumns( strHeadings, strValues ) + + EndMethod + + Function GetProcessOutput$(cmd$, flags$ = "") + + Local version$ + + ?Win32 + cmd:+".exe" + ? + + cmd=Quote(cmd) + If flags Then cmd:+" "+flags + + Local process:TProcess = CreateProcess(cmd,HIDECONSOLE) + + If process + Local bytes:Byte[] + Local tmpTimeout:Int = MilliSecs() + 500 + Repeat + Delay 10 + bytes=process.pipe.ReadPipe() + If bytes + version:+String.FromBytes(bytes,bytes.length) + EndIf + Until (Not process.status()) Or (MilliSecs() > tmpTimeout) + process.Close() + Return version.Trim().Replace("~r","") + EndIf + + Return LocalizeString("{{about_error_unavailable}}") + + EndFunction + + Method GetFASM$() + ?Not MacOS + Local tmpSections$[] = GetProcessOutput(BlitzMaxPath()+"/bin/fasm").Split("~n")[0].Split(" ") + Return tmpSections[tmpSections.length-1] + ? + EndMethod + + Method GetGCC$() + ?Win32 + If Not getenv_("MinGW") Then Return LocalizeString("{{about_error_notapplicable}}") + ? + Return GetProcessOutput("gcc", "-dumpversion").Split("~n")[0] + EndMethod + + Method GetGpp$() + ?Win32 + If Not getenv_("MinGW") Then Return LocalizeString("{{about_error_notapplicable}}") + ? + Return GetProcessOutput("g++", "-dumpversion").Split("~n")[0] + EndMethod + + Method PopulateColumns( strHeadings$[], strValues$[] ) + + strHeadings = strHeadings[..lblLeftAligned.length] + strValues = strValues[..lblRightAligned.length] + + For Local i:Int = 0 Until lblLeftAligned.length + LocalizeGadget( lblLeftAligned[i], strHeadings[i] ) + Next + + For Local i:Int = 0 Until lblRightAligned.length + SetGadgetText( lblRightAligned[i], strValues[i] ) + SetGadgetToolTip( lblRightAligned[i], strValues[i] ) + Next + + EndMethod + + Method Show() + PopulateText() + Super.Show() + EndMethod + + Method Poll() + Select EventSource() + Case window + If EventID()=EVENT_WINDOWCLOSE + Hide() + EndIf + Case cancel + If EventID()=EVENT_GADGETACTION + Hide() + EndIf + Default + Return 0 + End Select + Return 1 + End Method + + Function Create:TAboutRequester(host:TCodePlay) + + Local abt:TAboutRequester = New TAboutRequester + abt.initrequester(host,"{{about_window_title}}",420,255,STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL) + + Local win:TGadget = abt.window, w = ClientWidth(abt.window)-12, h = ClientHeight(abt.window) + + abt.pnlLogo = CreatePanel(w-(64-6),0,64,64,win) + SetGadgetLayout abt.pnlLogo, EDGE_CENTERED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED + + 'abt.pnlLogo = CreatePanel(0,0,64,64,win) + 'SetGadgetLayout abt.pnlLogo, EDGE_ALIGNED, EDGE_CENTERED, EDGE_ALIGNED, EDGE_CENTERED + + If Not pixLogo Then pixLogo = LoadPixmapPNG("incbin::bmxlogo.png") + SetGadgetPixmap abt.pnlLogo, pixLogo, PANELPIXMAP_CENTER + + Local y = 12 + + abt.lblTitle = CreateLabel("MaxIDE "+IDE_VERSION,6,y,w,18,win,LABEL_LEFT) + SetGadgetFont abt.lblTitle, LookupGuiFont( GUIFONT_SYSTEM, 12, FONT_BOLD ) + SetGadgetLayout abt.lblTitle, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED + y:+19 + + abt.lblSubtitle = CreateLabel("Copyright Blitz Research Ltd.",6,y,w,22,win,LABEL_LEFT) + SetGadgetFont abt.lblSubtitle, LookupGuiFont( GUIFONT_SYSTEM, 10, FONT_ITALIC ) + SetGadgetLayout abt.lblSubtitle, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED + + y = 64 + + SetGadgetLayout( CreateLabel("",6,y,w,4,win,LABEL_SEPARATOR), EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED ) + + y:+(4+6) + + Local tmpGadget:TGadget + + For y = y Until (255-21) Step 22 + + tmpGadget = CreateLabel("",6,y,135,22,win,LABEL_LEFT) + SetGadgetLayout( tmpGadget, EDGE_ALIGNED, EDGE_RELATIVE, EDGE_ALIGNED, EDGE_CENTERED ) + abt.lblLeftAligned:+[tmpGadget] + + tmpGadget = CreateLabel("",135+6,y,w-135,22,win,LABEL_LEFT) + SetGadgetLayout( tmpGadget, EDGE_RELATIVE, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED ) + DelocalizeGadget tmpGadget + abt.lblRightAligned:+[tmpGadget] + + Next + + abt.hypBlitz = CreateHyperlink("http://www.blitzbasic.com/",6,(h-28),200,26,win,LABEL_LEFT) + SetGadgetLayout abt.hypBlitz, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED, EDGE_ALIGNED + + Return abt + + EndFunction + + Function Spacer( height:Int, inpout:Int Var ) + inpout:+height+6 + Return height + EndFunction + +EndType + + +Type TCmdLineRequester Extends TRequester + Field label:TGadget,textfield:TGadget + + Method Poll() + Select EventSource() + Case window + If EventID()=EVENT_WINDOWCLOSE + Hide + EndIf + Case ok + If EventID()=EVENT_GADGETACTION + host.SetCommandLine TextFieldText(textfield) + Hide + EndIf + Case cancel + If EventID()=EVENT_GADGETACTION + SetGadgetText textfield,host.GetCommandLine() + Hide + EndIf + Default + Return 0 + End Select + Return 1 + End Method + + Method Show() + SetGadgetText textfield,host.GetCommandLine() + Super.Show() + ActivateGadget textfield + End Method + + Function Create:TCmdLineRequester(host:TCodePlay) + Local cmd:TCmdLineRequester = New TCmdLineRequester + cmd.initrequester(host,"{{cmdline_window_title}}",260,60,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL) + cmd.label=CreateLabel("{{cmdline_label_cmdline}}:",6,8,260,20,cmd.window) + cmd.textfield=CreateTextField(6,30,ClientWidth(cmd.window)-12,21,cmd.window) + Return cmd + End Function +End Type + +Type TGotoRequester Extends TRequester + Field linenumber:TGadget + + Method Show() + Super.Show() + ActivateGadget linenumber + End Method + + Method Poll() + Local line,data,text$ + Select EventSource() + Case linenumber + If EventID() = EVENT_GADGETACTION + text = GadgetText(linenumber) + If text And (Int(text) <> text) Then SetGadgetText linenumber, Int(text) + EndIf + Case window + If EventID()=EVENT_WINDOWCLOSE + Hide + EndIf + Case ok + line=Int(GadgetText(linenumber)) + Hide + host.activepanel.Invoke TOOLGOTO,String(line) + Case cancel + Hide + Default + Return 0 + End Select + Return 1 + End Method + + Function Create:TGotoRequester(host:TCodePlay) + Local seek:TGotoRequester = New TGotoRequester + seek.initrequester(host,"{{goto_window_title}}",260,66,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL,"{{goto_btn_goto}}") + CreateLabel("{{goto_label_linenum}}:",6,8+4,114,20,seek.window) + seek.linenumber=CreateTextField(150,8,ClientWidth(seek.window)-(150+6),21,seek.window) + SetGadgetFilter( seek.linenumber, IntegerFilter ) + Return seek + End Function + + Function IntegerFilter:Int( event:TEvent, context:Object ) + Select event.id + Case EVENT_KEYCHAR + If event.data >= Asc("0") And event.data <= Asc("9") Return True + If event.data = 8 Or event.data = 127 Or event.data = 13 Return True + Return False + Case EVENT_KEYDOWN + Return True + EndSelect + EndFunction + +End Type + +Type TColor + Field red,green,blue + + Method Set(rgb) + red=(rgb Shr 16)&$FF + green=(rgb Shr 8)&$FF + blue=rgb&$FF + End Method + + Method ToString$() + Return ""+red+","+green+","+blue + End Method + + Method FromString(s$) + Local p=s.Find(",")+1 + If Not p Return + Local q=s.Find(",",p)+1 + If Not q Return + red=Int(s[..p-1]) + green=Int(s[p..q-1]) + blue=Int(s[q..]) + End Method + + Method Request() + If RequestColor(red,green,blue) + red=RequestedRed() + green=RequestedGreen() + blue=RequestedBlue() + Return True + EndIf + End Method +End Type + +Type TTextStyle + + Field label:TGadget,panel:TGadget,combo:TGadget + Field underline:TGadget, color:TColor + Field flags + + Method Set(rgb,bolditalic) + color.set(rgb) + flags=bolditalic + End Method + + Method Format(textarea:TGadget,pos,length,emphasise:Int = False) + Local tmpFlags:Int = flags + If emphasise Then tmpFlags:|TEXTFORMAT_BOLD + FormatTextAreaText textarea,color.red,color.green,color.blue,tmpFlags,pos,length + End Method + + Method ToString$() + Return ""+color.red+","+color.green+","+color.blue+","+flags + End Method + + Method FromString(s$) + Local p,q,r + p=s.Find(",")+1;If Not p Return + q=s.Find(",",p)+1;If Not q Return + r=s.Find(",",q)+1;If Not r Return + color.red=Int(s[..p-1]) + color.green=Int(s[p..q-1]) + color.blue=Int(s[q..r-1]) + flags=Int(s[r..]) + End Method + + Method Poll() + Select EventSource() + Case panel + If EventID()=EVENT_MOUSEDOWN + Return color.Request() + EndIf + Case combo + flags=(flags&~3)|SelectedGadgetItem(combo) + Return True + Case underline + If EventData() Then flags:|TEXTFORMAT_UNDERLINE Else flags:&~TEXTFORMAT_UNDERLINE + Return True + End Select + End Method + + Method Refresh() + SetPanelColor panel,color.red,color.green,color.blue + SelectGadgetItem combo,flags&3 + SetButtonState(underline,(flags&TEXTFORMAT_UNDERLINE <> 0)) + End Method + + Function Create:TTextStyle(name$,xpos,ypos,window:TGadget) + Local s:TTextStyle + s=New TTextStyle + s.color=New TColor + s.label=CreateLabel(name,xpos,ypos+4,90,24,window) + s.panel=CreatePanel(xpos+94,ypos,24,24,window,PANEL_BORDER|PANEL_ACTIVE) + SetPanelColor s.panel,255,255,0 + s.combo=CreateComboBox(xpos+122,ypos,96,24,window) + s.underline=CreateButton("{{txtstyle_underline}}",xpos+226,ypos,ClientWidth(window)-(xpos+220),24,window,BUTTON_CHECKBOX) + AddGadgetItem s.combo,"{{txtstyle_normal}}",GADGETITEM_LOCALIZED + AddGadgetItem s.combo,"{{txtstyle_bold}}",GADGETITEM_LOCALIZED + AddGadgetItem s.combo,"{{txtstyle_italic}}",GADGETITEM_LOCALIZED + AddGadgetItem s.combo,"{{txtstyle_bolditalic}}",GADGETITEM_LOCALIZED + Return s + End Function +End Type + +Type TGadgetStyle + + Global fntLibrary:TGUIFont[] = [TGuiFont(Null), LookupGuiFont(GUIFONT_SYSTEM), LookupGuiFont(GUIFONT_MONOSPACED), .. + LookupGuiFont(GUIFONT_SANSSERIF), LookupGuiFont(GUIFONT_SERIF), .. + LookupGuiFont(GUIFONT_SCRIPT) ] + + Field label:TGadget,fpanel:TGadget,bpanel:TGadget,fcombo:TGadget,fbutton:TGadget + Field font_name$, font_size:Double + Field fg:TColor, bg:TColor + Field font_type = GUIFONT_SYSTEM, font:TGUIFont = fntLibrary[font_type] + + Method Apply(gadget:TGadget) + SetGadgetFont gadget,font + SetGadgetColor gadget,bg.red,bg.green,bg.blue,True + SetGadgetColor gadget,fg.red,fg.green,fg.blue,False + End Method + + Method Set(fg_rgb,bg_rgb,ftype,fname$="",fsize=0) + fg.set(fg_rgb) + bg.set(bg_rgb) + If Not fntLibrary[ftype] Then + font_name=fname + font_size=fsize + Else + font_name=FontName(fntLibrary[ftype]) + font_size=FontSize(fntLibrary[ftype]) + EndIf + font_type=ftype + End Method + + Method ToString$() + Return font_name+","+font_size+","+fg.ToString()+","+bg.ToString()+","+font_type + End Method + + Function GetArg$(a$ Var) + Local p = a.Find(",") + If p=-1 Then p=a.length + Local r$ = a$[..p] + a$=a$[p+1..] + Return r$ + End Function + + Method FromString(s$) + font_name=GetArg(s$) + font_size=Double(GetArg(s$)) + fg.red=Int(GetArg(s$)) + fg.green=Int(GetArg(s$)) + fg.blue=Int(GetArg(s$)) + bg.red=Int(GetArg(s$)) + bg.green=Int(GetArg(s$)) + bg.blue=Int(GetArg(s$)) + font_type=Int(GetArg(s$)) + If fntLibrary[font_type] Then + font_name=FontName(fntLibrary[font_type]) + font_size=FontSize(fntLibrary[font_type]) + EndIf + End Method + + Method Poll() + Local f:TGUIFont + Select EventSource() + Case fpanel + If EventID()=EVENT_MOUSEDOWN + Return fg.Request() + EndIf + Case bpanel + If EventID()=EVENT_MOUSEDOWN + Return bg.Request() + EndIf + Case fcombo, fbutton + If EventSource() = fcombo Then + If Not (EventData() < 0) Then + font_type = EventData() + f = fntLibrary[font_type] + EndIf + Else + font_type = 0 + SelectGadgetItem fcombo, font_type + EndIf + If Not f Then f=RequestFont(font) + If f + font_name=FontName(f) + font_size=FontSize(f) + Return True + EndIf + End Select + End Method + + Method Refresh() + font=fntLibrary[font_type] + If Not font Then font=LoadGuiFont(font_name,font_size) + SetPanelColor fpanel,fg.red,fg.green,fg.blue + SetPanelColor bpanel,bg.red,bg.green,bg.blue + SelectGadgetItem fcombo, font_type + Local tmpFloatText$[] = String(font_size).Split(".") + If tmpFloatText.length > 1 Then tmpFloatText[1] = tmpFloatText[1][..Min(2,tmpFloatText[1].length)] + SetGadgetText fbutton,font_name+" : "+".".Join(tmpFloatText)+"pt" + End Method + + Function Create:TGadgetStyle(name$,xpos,ypos,window:TGadget) + Local s:TGadgetStyle + s=New TGadgetStyle + s.fg=New TColor + s.bg=New TColor + s.label=CreateLabel(name,xpos,ypos+LABELOFFSET,66,50,window) + s.fpanel=CreatePanel(xpos+68,ypos,24,24,window,PANEL_BORDER|PANEL_ACTIVE) + s.bpanel=CreatePanel(xpos+96,ypos,24,24,window,PANEL_BORDER|PANEL_ACTIVE) + s.fbutton=CreateButton("..",xpos+122,ypos+30,ClientWidth(window)-(xpos+128),24,window) + s.fcombo=CreateComboBox(xpos+122,ypos,ClientWidth(window)-(xpos+128),24,window) + AddGadgetItem s.fcombo, "{{options_font_desc_user}}", GADGETITEM_DEFAULT|GADGETITEM_LOCALIZED + AddGadgetItem s.fcombo, "{{options_font_desc_guidefault}}", GADGETITEM_LOCALIZED + AddGadgetItem s.fcombo, "{{options_font_desc_monospaced}}", GADGETITEM_LOCALIZED + AddGadgetItem s.fcombo, "{{options_font_desc_sansserif}}", GADGETITEM_LOCALIZED + AddGadgetItem s.fcombo, "{{options_font_desc_serif}}", GADGETITEM_LOCALIZED + AddGadgetItem s.fcombo, "{{options_font_desc_script}}", GADGETITEM_LOCALIZED + Return s + End Function +End Type + +Const NORMAL=0 +Const COMMENT=1 +Const QUOTED=2 +Const KEYWORD=3 +Const NUMBER=4 +Const MATCHING=5 + +Type TOptionsRequester Extends TPanelRequester +' panels + Field optionspanel:TGadget,editorpanel:TGadget,toolpanel:TGadget +' settings + Field showtoolbar,restoreopenfiles,autocapitalize,syntaxhighlight,autobackup,autoindent,hideoutput + Field bracketmatching, externalhelp,systemkeys,sortcode + Field tabsize,language$ + Field editfontname$,editfontsize,editcolor:TColor + Field outputfontname$,outputfontsize,outputcolor:TColor +' states + Field editfont:TGUIFont +' gadgets + Field languages:TGadget + Field tabbutton:TGadget + Field editpanel:TGadget,editbutton:TGadget + Field buttons:TGadget[11] + Field styles:TTextStyle[] + Field textarea:TGadget + Field outputstyle:TGadgetStyle + Field navstyle:TGadgetStyle + Field dirty + Field undo:TBank + + Method Show() + RefreshGadgets() + Super.Show() + EndMethod + + Method Snapshot() + If Not undo undo=CreateBank(8192) + Local stream:TStream=CreateBankStream(undo) + write stream + stream.close + End Method + + Method Restore() + If Not undo Return + Local stream:TStream=CreateBankStream(undo) + Read stream + stream.close + End Method + + Method SetDefaults() + language=DEFAULT_LANGUAGEPATH + bracketmatching=True + showtoolbar=True + restoreopenfiles=True + autocapitalize=True + syntaxhighlight=True + autobackup=True + autoindent=True + tabsize=4 + editfontname$=FontName(TGadgetStyle.fntLibrary[GUIFONT_MONOSPACED]) + editfontsize=FontSize(TGadgetStyle.fntLibrary[GUIFONT_MONOSPACED]) + editcolor.set( $334455 ) + styles[NORMAL].set( $ffffff,0 ) + styles[COMMENT].set( $bbeeff,0 ) + styles[QUOTED].set( $00ff66,0 ) + styles[KEYWORD].set( $ffff00,0 ) + styles[NUMBER].set( $40ffff,0 ) + styles[MATCHING].set( $ff4040,TEXTFORMAT_BOLD ) + outputstyle.set(0,-1,GUIFONT_MONOSPACED) + navstyle.set(0,-1,GUIFONT_SYSTEM) + RefreshGadgets + End Method + + Method Write(stream:TStream) + stream.WriteLine "[Options]" + stream.WriteLine "language="+language + stream.WriteLine "showtoolbar="+showtoolbar + stream.WriteLine "restoreopenfiles="+restoreopenfiles + stream.WriteLine "autocapitalize="+autocapitalize + stream.WriteLine "syntaxhighlight="+syntaxhighlight + stream.WriteLine "bracketmatching="+bracketmatching + stream.WriteLine "autobackup="+autobackup + stream.WriteLine "autoindent="+autoindent + stream.WriteLine "tabsize="+tabsize + stream.WriteLine "editfontname="+editfontname + stream.WriteLine "editfontsize="+editfontsize + stream.WriteLine "editcolor="+editcolor.ToString() + stream.WriteLine "normal_style="+styles[NORMAL].ToString() + stream.WriteLine "comment_style="+styles[COMMENT].ToString() + stream.WriteLine "quote_style="+styles[QUOTED].ToString() + stream.WriteLine "keyword_style="+styles[KEYWORD].ToString() + stream.WriteLine "number_style="+styles[NUMBER].ToString() + stream.WriteLine "matched_style="+styles[MATCHING].ToString() + stream.WriteLine "console_style="+outputstyle.ToString() 'Renamed from 'output_style' to bump users to default monospace font. + stream.WriteLine "navi_style="+navstyle.ToString() 'Renamed from 'nav_style' to bump users to default treeview font. + stream.WriteLine "hide_output="+hideoutput + stream.WriteLine "external_help="+externalhelp + stream.WriteLine "system_keys="+systemkeys + stream.WriteLine "sort_code="+sortcode + End Method + + Method Read(stream:TStream) + Local f$,p,a$,b$,t + While Not stream.Eof() + f$=stream.ReadLine() + If f$="" Or (f$[..1]="[" And f$<>"[Options]") Exit + p=f.find("=") + a$=f[..p] + b$=f[p+1..] + t=Int(b) + Select a$ + Case "showtoolbar" showtoolbar=t + Case "restoreopenfiles" restoreopenfiles=t + Case "autocapitalize" autocapitalize=t + Case "syntaxhighlight" syntaxhighlight=t + Case "bracketmatching" bracketmatching=t + Case "autobackup" autobackup=t + Case "autoindent" autoindent=t + Case "tabsize" tabsize=t + Case "editfontname" editfontname=b + Case "editfontsize" editfontsize=t + Case "editcolor" editcolor.FromString(b) + Case "normal_style" styles[NORMAL].FromString(b) + Case "comment_style" styles[COMMENT].FromString(b) + Case "quote_style" styles[QUOTED].FromString(b) + Case "keyword_style" styles[KEYWORD].FromString(b) + Case "number_style" styles[NUMBER].FromString(b) + Case "matched_style" styles[MATCHING].FromString(b) + Case "console_style" outputstyle.FromString(b) 'Renamed from 'output_style' to bump users to default monospace font. + Case "navi_style" navstyle.FromString(b) 'Renamed from 'nav_style' to bump users to default treeview font. + Case "hide_output" hideoutput=t + Case "external_help" externalhelp=t + Case "system_keys" systemkeys=t + Case "sort_code" sortcode=t + Case "language" + Try + Local tmpLanguage:TMaxGUILanguage = LoadLanguage(host.FullPath(b)) + If tmpLanguage Then + language = b + SetLocalizationLanguage tmpLanguage + host.RefreshMenu() + EndIf + Catch excn:Object + EndTry + End Select + Wend + RefreshGadgets + End Method + + Method RefreshGadgets() + Local rgb:TColor,flags + editfont=LoadGuiFont(editfontname,editfontsize) + + 'Language Loading / Enumeration + ClearGadgetItems languages + AddGadgetItem languages, "English (English) [Embedded]", GADGETITEM_DEFAULT,-1,"",DEFAULT_LANGUAGEPATH + For Local tmpFile$ = EachIn LoadDir( host.bmxpath+"/cfg", True ) + Local tmpPath$ = host.bmxpath+"/cfg/"+tmpFile + If FileType(tmpPath) = FILETYPE_FILE And tmpFile.ToLower().EndsWith(".language.ini") Then + If tmpPath = host.FullPath(language) Then flags = GADGETITEM_DEFAULT Else flags = 0 + AddGadgetItem languages, tmpFile.Split(".")[0], flags, -1, "", "$BMXPATH/cfg/"+tmpFile + EndIf + Next + + SetButtonState buttons[0],showtoolbar + SetButtonState buttons[1],restoreopenfiles + SetButtonState buttons[2],autocapitalize + SetButtonState buttons[3],syntaxhighlight + SetButtonState buttons[4],bracketmatching + SetButtonState buttons[5],autobackup + SetButtonState buttons[6],autoindent + SetButtonState buttons[7],hideoutput + SetButtonState buttons[8],externalhelp + SetButtonState buttons[9],systemkeys + SetButtonState buttons[10],sortcode + SelectGadgetItem tabbutton,Min(Max(tabsize/2-1,0),7) + SetPanelColor editpanel,editcolor.red,editcolor.green,editcolor.blue + SetGadgetText editbutton,editfontname+" : "+editfontsize + "pt" + For Local i:Int = 0 Until styles.length + styles[i].Refresh + Next + LockTextArea textarea + SetTextAreaColor textarea,editcolor.red,editcolor.green,editcolor.blue,True + SetGadgetFont textarea,editfont + styles[NORMAL].format(textarea,0,TEXTAREA_ALL) + styles[COMMENT].format(textarea,0,12) + styles[MATCHING].format(textarea,24,1) + styles[NUMBER].format(textarea,25,3) + styles[NUMBER].format(textarea,31,1) + styles[MATCHING].format(textarea,32,1) + styles[NUMBER].format(textarea,36,1) + styles[KEYWORD].format(textarea,39,5) + styles[QUOTED].format(textarea,46,10) + UnlockTextArea textarea + outputstyle.Refresh + navstyle.Refresh + dirty=True + End Method + + Method Poll() + Local font:TGUIFont,refresh,processed = 1 + For Local i:Int = 0 Until styles.length + refresh:|styles[i].Poll() + Next + refresh:|outputstyle.Poll() + refresh:|navstyle.Poll() + Select EventID() + Case EVENT_GADGETACTION, EVENT_WINDOWCLOSE + Select EventSource() + Case buttons[0];showtoolbar=ButtonState(buttons[0]);dirty=True + Case buttons[1];restoreopenfiles=ButtonState(buttons[1]) + Case buttons[2];autocapitalize=ButtonState(buttons[2]);dirty=True + Case buttons[3];syntaxhighlight=ButtonState(buttons[3]);dirty=True + Case buttons[4];bracketmatching=ButtonState(buttons[4]) + Case buttons[5];autobackup=ButtonState(buttons[5]) + Case buttons[6];autoindent=ButtonState(buttons[6]) + Case buttons[7];hideoutput=ButtonState(buttons[7]) + Case buttons[8];externalhelp=ButtonState(buttons[8]) + Case buttons[9];systemkeys=ButtonState(buttons[9]);dirty=2 + Case buttons[10];sortcode=ButtonState(buttons[10]);dirty=3 + Case tabber;SetPanelIndex SelectedGadgetItem(tabber) + Case ok + Hide() + Select dirty + Case 1 + host.RefreshAll + Case 2 + host.Restart + End Select + dirty=False + SnapShot() + Case window + If EventID()=EVENT_WINDOWCLOSE + Restore() + dirty=False + Hide() + EndIf + Case cancel + Restore() + dirty=False + Hide() + Case tabbutton + tabsize=(SelectedGadgetItem(tabbutton)+1)*2 + refresh=True + Case editpanel + If EventID()=EVENT_MOUSEDOWN + refresh=editcolor.Request() + EndIf + Case editbutton + font=RequestFont(editfont) + If font + editfontname=FontName(font) + editfontsize=FontSize(font) + refresh=True + EndIf + Case languages + If EventData() > 0 Then + language = String(GadgetItemExtra(languages,EventData())) + SetLocalizationLanguage TMaxGUILanguage(LoadLanguage(host.FullPath(language))) + Else + language = DEFAULT_LANGUAGEPATH + SetLocalizationLanguage defaultLanguage + EndIf + host.RefreshMenu() + Default + processed = 0 + EndSelect + Case EVENT_MOUSEDOWN + Select EventSource() + Case editpanel + If EventID()=EVENT_MOUSEDOWN + editcolor.Request() + refresh=True + EndIf + Default + processed = 0 + EndSelect + EndSelect + If refresh Then RefreshGadgets() + Return processed + End Method + + Method InitOptionsRequester(host:TCodePlay) + Local w:TGadget + InitPanelRequester(host,"{{options_window_title}}",380,430) +' init values + editcolor=New TColor +' init gadgets + optionspanel=AddPanel("{{options_optionstab}}") + editorpanel=AddPanel("{{options_editortab}}") + toolpanel=AddPanel("{{options_toolstab}}") + + SetGadgetShape( tabber, GadgetX(tabber), GadgetY(tabber)+32, GadgetWidth(tabber), GadgetHeight(tabber)-32 ) + + w=window + CreateLabel("{{options_options_label_language}}:",6,6+4,80,24,w) + languages = CreateComboBox(90,6,ClientWidth(w)-96,26,w) + + w=optionspanel + + buttons[0]=CreateButton("{{options_options_btn_showtoolbar}}",6,6,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX) + buttons[1]=CreateButton("{{options_options_btn_autorestore}}",6,34,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX) + buttons[2]=CreateButton("{{options_options_btn_autocaps}}",6,60,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX) + buttons[3]=CreateButton("{{options_options_btn_syntaxhighlight}}",6,86,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX) + buttons[4]=CreateButton("{{options_options_btn_bracketmatching}}",6,112,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX) + buttons[5]=CreateButton("{{options_options_btn_autobackup}}",6,138,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX) + buttons[6]=CreateButton("{{options_options_btn_autoindent}}",6,164,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX) + buttons[7]=CreateButton("{{options_options_btn_autohideoutput}}",6,190,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX) + buttons[8]=CreateButton("{{options_options_btn_useexternalbrowser}}",6,216,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX) + buttons[9]=CreateButton("{{options_options_btn_osshortcuts}}",6,242,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX) + buttons[10]=CreateButton("{{options_options_btn_sortcodeviewnodes}}",6,268,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX) + + w=editorpanel + CreateLabel("{{options_editor_label_background}}:",6,6+4,90,24,w) + editpanel=CreatePanel(100,6,24,24,w,PANEL_BORDER|PANEL_ACTIVE) + editbutton=CreateButton("..",128,6,ClientWidth(w)-134,24,w) + + tabbutton=CreateComboBox(128,36,ClientWidth(w)-134,24,w) + For Local i=1 To 8 + AddGadgetItem tabbutton,"{{options_editor_itemlabel_tabsize}} "+(i*2),GADGETITEM_LOCALIZED + Next + + styles=New TTextStyle[6] + styles[NORMAL]=TTextStyle.Create("{{options_editor_label_plaintext}}:",6,66,w) + styles[COMMENT]=TTextStyle.Create("{{options_editor_label_remarks}}:",6,96,w) + styles[QUOTED]=TTextStyle.Create("{{options_editor_label_strings}}:",6,126,w) + styles[KEYWORD]=TTextStyle.Create("{{options_editor_label_keywords}}:",6,156,w) + styles[NUMBER]=TTextStyle.Create("{{options_editor_label_numbers}}:",6,186,w) + styles[MATCHING]=TTextStyle.Create("{{options_editor_label_matchings}}:",6,216,w) + + textarea=CreateTextArea(6,250,ClientWidth(w)-12,ClientHeight(w)-256,w,TEXTAREA_READONLY) + SetGadgetText textarea,"'Sample Code~n~nresult = ((2.0 * 4) + 1)~nPrint( ~qResult: ~q + result )~n" + + w=toolpanel + outputstyle=TGadgetStyle.Create("{{options_tools_label_output}}: ",6,6,w) + navstyle=TGadgetStyle.Create("{{options_tools_label_navbar}}: ",6,66,w) + + SetDefaults() + SetPanel optionspanel + + SnapShot + End Method + + Function Create:TOptionsRequester(host:TCodePlay) + Local o:TOptionsRequester + o=New TOptionsRequester + o.InitOptionsRequester host + Return o + End Function + +End Type + +Type TFindRequester Extends TRequester + Field findterm:TGadget + + Method ShowFind(term$="") + If term SetGadgetText(findterm,term) + Super.Show() + ActivateGadget findterm + End Method + + Method Poll() + Local find$,data + Select EventSource() + Case window + If EventID()=EVENT_WINDOWCLOSE + Hide() + EndIf + Case ok + If EventID() = EVENT_GADGETACTION + If TextFieldText(findterm) + find=TextFieldText(findterm) + Hide() + host.activepanel.Invoke TOOLFINDNEXT,find + Else + Notify LocalizeString("{{search_error_nosearchstring}}"), True + ActivateGadget findterm + EndIf + EndIf + Case cancel + If EventID() = EVENT_GADGETACTION Then Hide() + Default + Return 0 + End Select + Return 1 + End Method + + Function Create:TFindRequester(host:TCodePlay) + Local seek:TFindRequester + seek=New TFindRequester + seek.initrequester(host,"{{find_window_title}}",280,66,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL,"{{find_btn_find}}") + CreateLabel("{{find_label_find}}:",6,12,82,24,seek.window) + seek.findterm=CreateTextField(88,8,ClientWidth(seek.window)-(88+6),21,seek.window) + Return seek + End Function +End Type + +Type TReplaceRequester Extends TRequester + Field findterm:TGadget,replaceterm:TGadget + Field findnext:TGadget,replaceit:TGadget,replaceall:TGadget + + Method Show() + Super.Show() + ActivateGadget findterm + End Method + + Method Poll() + Local find$,Replace$ + Select EventSource() + Case window + If EventID()=EVENT_WINDOWCLOSE + Hide() + EndIf + Case cancel + If EventID() = EVENT_GADGETACTION Then Hide + Case ok + If EventID() = EVENT_GADGETACTION Then + If TextFieldText(findterm) Then + find=TextFieldText(findterm) + host.activepanel.Invoke TOOLFINDNEXT,find + Else + Notify LocalizeString("{{search_error_nosearchstring}}"), True + ActivateGadget findterm + EndIf + EndIf + Case replaceit + If EventID() = EVENT_GADGETACTION Then + Replace=TextFieldText(replaceterm) + If host.activepanel.Invoke(TOOLREPLACE,Replace) + host.activepanel.Invoke TOOLFINDNEXT,find + EndIf + EndIf + Case replaceall + If EventID() = EVENT_GADGETACTION Then + find=TextFieldText(findterm) + Replace=TextFieldText(replaceterm) + host.activepanel.Invoke TOOLREPLACE,find+Chr(0)+Replace + EndIf + Default + Return 0 + End Select + Return 1 + End Method + + Function Create:TReplaceRequester(host:TCodePlay) + Local x,y + Local seek:TReplaceRequester + seek=New TReplaceRequester + seek.initrequester(host,"{{replace_window_title}}",380,80,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER,"{{replace_btn_findnext}}") + + y=11 + CreateLabel( "{{replace_label_find}}:",6,y+4,88,24,seek.window ) + seek.findterm=CreateTextField( 96,y,168,21,seek.window ) + + y:+32 + CreateLabel( "{{replace_label_replacewith}}:",6,y+4,88,24,seek.window ) + seek.replaceterm=CreateTextField( 96,y,168,21,seek.window ) + + x=ClientWidth(seek.window)-102 + y=8 + seek.replaceit=CreateButton("{{replace_btn_replace}}",x,y,96,26,seek.window) + seek.replaceall=CreateButton("{{replace_btn_replaceall}}",x,y+32,96,26,seek.window) + + Return seek + End Function +End Type + +Type TEventHandler Extends TTool + Method OnEvent() Abstract +End Type + +Type TToolPanel Extends TEventHandler + Field name$,path$ + Field panel:TGadget + Field index + Field active + + Method Show() + End Method +End Type + +Type TView + Field node:TGadget + Field state +End Type + +Type TNode Extends TTool + Const HIDESTATE=0 + Const CLOSEDSTATE=1 + Const OPENSTATE=2 + + Field name$,sortname$ + Field parent:TNode + Field kids:TList=New TList + Field views:TView[] +' activate program + Field target:TTool + Field action + Field argument:Object + + Method SortKids( ascending=True ) + Local term:TLink=kids._head + Repeat + Local link:TLink=kids._head._succ + Local sorted=True + Repeat + Local succ:TLink=link._succ + If succ=term Exit + Local cc=TNode(link._value).sortname.Compare( TNode(succ._value).sortname ) + If (cc>0 And ascending) Or (cc<0 And Not ascending) + Local link_pred:TLink=link._pred + Local succ_succ:TLink=succ._succ + link_pred._succ=succ + succ._succ=link + succ._pred=link_pred + link._succ=succ_succ + link._pred=succ + succ_succ._pred=link + sorted=False + Else + link=succ + EndIf + Forever + If sorted Return + term=link + Forever + End Method + + Method FindArgument:TNode(arg:Object) + Local n:TNode,r:TNode,a$ + If arg.Compare(argument)=0 Return Self + a$=(String(arg)).ToLower() + If a And a=(String(argument)).toLower() Return Self + For n=EachIn kids + r=n.FindArgument(arg) + If r Return r + Next + End Method + + ?Debug + Method Dump(indent$="") + Local n:TNode + Print indent+name + indent:+"~t" + For n=EachIn kids + n.Dump indent + Next + End Method + ? + + Method IsHidden() + Local v:TView + If Not parent Return False + For v=EachIn parent.views + If v.state=OPENSTATE Return False + Next + Return True + End Method + + Method SetAction(tool:TTool,cmd,arg:Object=Null) + target=tool + action=cmd + argument=arg + End Method + + Method Hide(v:TView=Null) 'null means hide in all views + For Local n:TNode = EachIn kids + n.hide v + Next + If v + If v.node FreeTreeViewNode v.node;v.node=Null + Else + For v=EachIn views + If v.node FreeTreeViewNode v.node;v.node=Null + Next + EndIf + End Method + + Method Detach() + Hide() + If parent parent.kids.remove Self;parent=Null + End Method + + Method FreeKids() + For Local n:TNode = EachIn kids + n.free + Next + End Method + + Method Free() + FreeKids() + Detach() + target=Null;argument=Null;views=Null + End Method + + Method Invoke(command,arg:Object=Null) + Select command + Case TOOLACTIVATE + If target Return target.Invoke(action,argument) + End Select + End Method + + Method Find:TNode(treeviewnode:TGadget,view=0) + Local n:TNode,r:TNode + Local v:TView + v=getview(view) + If v And v.node=treeviewnode Return Self + For n=EachIn kids + r=n.Find(treeviewnode,view) + If r Return r + Next + End Method + + Method SetNode(treeviewnode:TGadget,view=0) + Local v:TView = getview(view) + v.node=treeviewnode + open view + End Method + + Method HighLight(view=-1) + Local v:TView + If view=-1 + For view=0 Until views.length + HighLight view + Next + Return + EndIf + v=GetView(view) + If v.node SelectTreeViewNode v.node + End Method + + Method Open(view=-1) + Local v:TView + If view=-1 + For view=0 Until views.length + Open view + Next + Return + EndIf + v=GetView(view) + If v.state<>OPENSTATE + v.state=OPENSTATE + RefreshView view +' If v.node ExpandTreeViewNode v.node + EndIf + End Method + + Method Close(view=0) + Local v:TView = GetView(view) + If v.state<>CLOSEDSTATE + v.state=CLOSEDSTATE +' If v.node CollapseTreeViewNode v.node + EndIf + End Method + + Method GetState(view=0) + Return GetView(view).state + End Method + + Method GetView:TView(view=0) + If view>=views.length + views=views[..view+1] + EndIf + If Not views[view] views[view] = New TView + Return views[view] + End Method + + Method GetIndex() + Local node:TNode + Local i + If parent + For node=EachIn parent.kids + If node=Self Return i + i:+1 + Next + EndIf + End Method + + Method Refresh() + For Local i:Int = 0 Until views.length + RefreshView i + Next + End Method + + Method RefreshView(view=0) + Local n:TNode,quick,nodeToOpen:TGadget + Local v:TView,vv:TView + Local node + If parent And parent.getstate(view)=CLOSEDSTATE quick=True + v=getview(view) + If v.node And parent + If GadgetText(v.node) <> name Then + ModifyTreeViewNode v.node,name + LocalizeGadget(v.node,name,"") + EndIf + If v.state=OPENSTATE nodeToOpen = v.node;quick = False + Else + If parent And name + vv=parent.getview(view) + If vv.node + v.node=InsertTreeViewNode(GetIndex(),name,vv.node) + If v.state=HIDESTATE v.state=CLOSEDSTATE + If vv.state=OPENSTATE nodeToOpen = vv.node + quick=False + EndIf + EndIf + EndIf + If quick Return + If Not kids Return + For n=EachIn kids + n.RefreshView view + Next + If nodeToOpen Then ExpandTreeViewNode nodeToOpen + End Method + + Method NodeAfter:TNode(node:TNode) + Local link:TLink + If node link=kids.FindLink(node) + If link link=link.NextLink() + If link Return TNode(link.Value()) + End Method + + Method Sync(snap:TNode) + Local snapkid:TNode + Local currentkid:TNode + Local kid:TNode + Local t:TNode + Local link:TLink + + If snap.name<>name Return + If kids.Count() currentkid=TNode(kids.First()) + For snapkid=EachIn snap.kids +' if same name in list + kid=currentkid + While kid + If kid.name=snapkid.name Exit + kid=NodeAfter(kid) + Wend +' then remove entries in front + If kid + While currentkid<>kid + t=currentkid + currentkid=NodeAfter(currentkid) + t.free() + Wend + EndIf +' if same name sync else insert + If currentkid And currentkid.name=snapkid.name 'merge values if same name + currentkid.Sync snapkid + currentkid=NodeAfter(currentkid) + Else + snapkid.detach + If currentkid + link=kids.FindLink(currentkid) + kids.InsertBeforeLink snapkid,link + Else + kids.AddLast snapkid + EndIf + snapkid.parent=Self + EndIf + Next +' remove any entries at end + While currentkid + t=currentkid + currentkid=NodeAfter(currentkid) + t.free() + Wend + Refresh() + End Method + + Method SetName(n$) + name=n + End Method + + Method AddNode:TNode(name$) + Local v:TNode + v=New TNode + v.setname name + Append v + Return v + End Method + + Method Append(v:TNode) + v.parent=Self + kids.AddLast v + End Method + + Function CreateNode:TNode(name$) + Local node:TNode + node=New TNode + node.setname name + Return node + End Function + +End Type + +Type THelpPanel Extends TToolPanel + + Field host:TCodePlay + Field htmlview:TGadget + + Method AddLink:TNode(parent:TNode,name$,href$) + Local n:TNode + If parent + n=parent.AddNode(name) + Else + n=host.helproot + EndIf + If href href=RealPath(href) + n.SetAction(Self,TOOLNAVIGATE,href) + Return n + End Method + + Method ImportLinks( node:TNode,path$ ) + + Local t$=path+"/index.html" + If FileType( t )<>FILETYPE_FILE Return + + node=AddLink( node,StripDir( path ),t ) + + Local map:TMap=New TMap + + 'scan for html files + For Local e$=EachIn LoadDir( path ) + If e="index.html" Continue + Local p$=path+"/"+e + Select FileType( p ) + Case FILETYPE_DIR + ImportLinks node,p + Case FILETYPE_FILE + If Not e.StartsWith( "_" ) And ExtractExt( e ).Tolower()="html" + map.Insert StripExt( e ),p + EndIf + End Select + Next + + 'scan for anchors in index.html... + ' + 'note: anchors must be quote enclosed and of simple form + Local c$=CacheAndLoadText( t ),i + Repeat + i=c.Find( "",i ) + If i2=-1 Exit + Local q$=c[i..i2] + If q.StartsWith( "_" ) Continue + map.Insert q,t+"#"+q + i=i2+1 + Forever + + For Local kv:TKeyValue=EachIn map + AddLink node,String( kv.Key() ),String( kv.Value() ) + Next + + End Method + + Method SyncDocs() + host.helproot.FreeKids + + ImportLinks Null,host.bmxpath+"/docs/html" + + Local link:TNode + For Local m$=EachIn EnumModules() + If m.StartsWith( "brl." ) Or m.StartsWith( "pub." ) Or m.StartsWith("maxgui.") Continue + Local p$=ModulePath( m )+"/doc/commands.html" + If FileType( p )<>FILETYPE_FILE Continue + If Not link link=AddLink( host.helproot,"{{navnode_thirdpartymods}}","" ) + AddLink link,m,p + Next + + link=AddLink( host.helproot,"{{navnode_moduleindex}}","" ) + + If FileType( host.bmxpath+"/docs/html/Modules/commands.txt" )=FILETYPE_FILE + Local comm$=CacheAndLoadText( host.bmxpath+"/docs/html/Modules/commands.txt" ) + For Local line$=EachIn comm.Split( "~n" ) + Local bits$[]=line.Split( "|" ) + If bits.length<>2 Continue + Local i=bits[0].Find( " : " ) + If i<>-1 bits[0]=bits[0][..i] + AddLink link,bits[0],host.bmxpath+bits[1] + Next + EndIf + + host.helproot.Refresh + End Method + + Method Invoke(command,argument:Object=Null) + Local href$ + If Not htmlview Return + Select command + Case TOOLCUT + GadgetCut htmlview + Case TOOLCOPY + GadgetCopy htmlview + Case TOOLPASTE + GadgetPaste htmlview + Case TOOLSHOW + ActivateGadget htmlview + host.SetTitle + Case TOOLNAVIGATE + href$=String(argument) + If href Go href + Case TOOLPRINT + GadgetPrint htmlview + End Select + End Method + + Method OnEvent() + Local url$,p,t$ + If EventSource()=htmlview + Select EventID() + Case EVENT_GADGETACTION 'NAVIGATEREQUEST + url$=String( EventExtra() ) + If url[..5]="http:" + OpenURL url + Else + p=url.findlast(".") + If p>-1 + t$=url[p..].tolower() + If t$=".bmx" + If url.Find( "file://" )=0 + url=url[7..] + ?Win32 + url=url[1..] + ? + EndIf + url=url.Replace("%20"," ") + Local source:TOpenCode=host.OpenSource(url) + If source source.MakePathTemp + Else + url=url.Replace("\","/") + url=url.Replace("user/index","user/welcome") + url=url.Replace("lang/index","lang/welcome") + url=url.Replace("mods/index","mods/welcome") + Go url$ + EndIf + EndIf + EndIf + End Select + EndIf + End Method + + Method Go(url$,internal=False) + Local node:TNode + + If host.options.externalhelp And Not internal + PollSystem + OpenURL url + MinimizeWindow host.window + PollSystem + Return + EndIf + + HtmlViewGo htmlview,url + host.SelectPanel Self + node=host.helproot.FindArgument(RealPath(url)) + If node + node.Highlight +' Else +' print "node not found" + EndIf + ActivateGadget htmlview + End Method + + Method Home() + Go host.bmxpath+HOMEPAGE,True + End Method + + Method Forward() + HtmlViewForward htmlview + End Method + + Method Back() + HtmlViewBack htmlview + End Method + + Function Create:THelpPanel(host:TCodePlay) + Local root,style + Local p:THelpPanel = New THelpPanel + p.host=host + p.name="{{tab_help}}" + codeplay.addpanel(p) + style=HTMLVIEW_NONAVIGATE 'HTMLVIEW_NOCONTEXTMENU + p.htmlview=CreateHTMLView(0,0,ClientWidth(p.panel),ClientHeight(p.panel),p.panel,style) + SetGadgetLayout p.htmlview,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED +' p.Home + p.SyncDocs + Return p + End Function + +End Type + +Type TSearchResult + + Field filepath$ + Field char%, line% + Field linestring$ + + Method AddToListbox( pGadget:TGadget ) + AddGadgetItem pGadget, "[" + line + ", " + char + "] " + filepath, 0, -1, StripWhitespace(linestring,char), Self + EndMethod + + Method Set:TSearchResult(pFilePath$,pChar%,pLine%,pLineString$) + filepath = pFilePath + char = pChar + line = pLine + linestring = pLineString + Return Self + EndMethod + + Function StripWhitespace$(pString$,pChar%) + If pString.length < pChar Then Return pString + Local outString$ + For Local i:Int = 0 Until pString.length + Select pString[i] + Case Asc(" "), Asc("~t"), Asc("~n"), Asc("~r") + If outString And Not outString.EndsWith(" ") Then outString:+" " + Default + outString:+pString[i..i+1] + EndSelect + Next + Return outString + EndFunction + +EndType + +Type TSearchRequester Extends TRequester + + Const strSearchText$ = "{{search_btn_startsearch}}", strStopSearchText$ = "{{search_btn_stopsearch}}" + + Global strFileExts$[][] = [["bmx"],filetypes.Split(","),String[](Null)] + + Field findbox:TGadget,typebox:TGadget,pathbox:TGadget,pathbutton:TGadget,pathsubdir:TGadget,results:TGadget + Field lstSearchResults:TList = New TList + + Field safetyCount% = -1, safetyThreshold = 500, safetyResetCount% = 0 + + Method Poll() + Local id:Int = EventID() + Local data:Int = EventData() + Select EventSource() + Case results + Select id + Case EVENT_GADGETACTION + Local tmpSearchResult:TSearchResult = TSearchResult(EventExtra()) + If tmpSearchResult Then + host.DebugSource( tmpSearchResult.filepath, tmpSearchResult.line, tmpSearchResult.char ) + 'Hide() + EndIf + EndSelect + Case pathbutton + If EventID()=EVENT_GADGETACTION + Local tmpString$ = RequestDir( LocalizeString("{{search_requestfolder_title}}"),GadgetText(pathbox)) + If tmpString Then SetGadgetText(pathbox,tmpString) + EndIf + Case window + If EventID()=EVENT_WINDOWCLOSE Then Hide() + Case findbox + If EventID() = EVENT_GADGETACTION Then + If GadgetText(findbox) Then EnableGadget(ok) Else DisableGadget(ok) + EndIf + Case ok + If EventID()=EVENT_GADGETACTION + If safetyCount < 0 Then StartSearch() Else safetyCount = -2 + EndIf + Case cancel + If EventID()=EVENT_GADGETACTION Then Hide() + End Select + End Method + + Method Hide() + safetyCount = -2 + Super.Hide() + EndMethod + + Method ShowWithPath( pPath$ ) + If pPath Then SetGadgetText( pathbox, pPath ) + Show() + ActivateGadget( findbox ) + EndMethod + + Method StartSearch() + + PollSystem() + + Select FileType(RealPath(GadgetText(pathbox))) + Case FILETYPE_NONE + Notify LocalizeString("{{search_error_pathnotfound}}"),True + ActivateGadget(pathbox) + Return + Case FILETYPE_FILE + Notify LocalizeString("{{search_error_pathisfile}}"),True + ActivateGadget(pathbox) + Return + EndSelect + + If Not GadgetText(findbox) Then + Notify LocalizeString("{{search_error_nosearchstring}}"),True + ActivateGadget(findbox);Return + EndIf + + safetyResetCount = 0;safetyCount = 0 + LocalizeGadget ok, strStopSearchText;ClearGadgetItems results + SearchPath( GadgetText(pathbox), strFileExts[SelectedGadgetItem(typebox)], GadgetText(findbox).ToLower(), ButtonState(pathsubdir) ) + LocalizeGadget ok, strSearchText;safetyCount = -1 + SetStatusText window, LocalizeString("{{search_msg_complete}}").Replace("%1",CountGadgetItems(results)) + + EndMethod + + Method SearchPath(pPath$,pFileType$[],pString$,pRecurse% = True) + + pPath$ = RealPath(pPath) 'Make sure we are using a real path + + Local tmpSearchDir$[] = LoadDir(pPath,True) 'Load directors contents into string array + If Not tmpSearchDir Then Return 'Return if the directory is invalid + tmpSearchDir.Sort() 'Sort the contents alphabetically + + SetStatusText window, LocalizeString("{{search_msg_searchingdir}}").Replace("%1", pPath) 'And let user know which directory is being searched + + Local tmpFullPath$ + + For Local tmpItem$ = EachIn tmpSearchDir + + tmpFullPath = pPath + "/" + tmpItem + + Select FileType(tmpFullPath) + Case FILETYPE_NONE;Continue 'Skip item if, for whatever reason, it doesn't exist + Case FILETYPE_FILE 'If file, then check extension and search if valid + If Not pFileType + SearchFile(tmpFullPath,pString) + Else + Local tmpExt$ = ExtractExt(tmpFullPath).ToLower$() + For Local tmpValidExt$ = EachIn pFileType + If tmpExt = tmpValidExt Then SearchFile(tmpFullPath,pString) + Next + EndIf + Case FILETYPE_DIR 'If folder, then we might have to search recursively + If pRecurse Then SearchPath(tmpFullPath,pFileType,pString,pRecurse) + EndSelect + + If Not ShouldContinue() Then Return + + Next + + PollSystem();If PeekEvent() Then host.Poll() 'Let the system update as we could be searching a while + + EndMethod + + Method SearchFile(pPath$,pString$) + Local tmpText$ = CacheAndLoadText( pPath ), tmpLines$[], tmpFindPos%, tmpCharCount%, tmpLineNo% + Local tmpStringLength% = pString.length, tmpChunkLines$[], tmpPrevLines$ + + If tmpText Then + tmpLines = tmpText.Split("~n") + tmpText = tmpText.ToLower() + tmpFindPos = tmpText.Find(pString) + While ShouldContinue() And tmpFindPos > -1 + tmpChunkLines = tmpText[..tmpFindPos].Split("~n") + tmpPrevLines = "~n".Join(tmpChunkLines[..tmpChunkLines.length-1]) + tmpLineNo:+(tmpChunkLines.length)-1 + Local tmpSearchResult:TSearchResult = New TSearchResult.Set(pPath,tmpFindPos-tmpPrevLines.length,tmpLineNo+1,tmpLines[tmpLineNo]) + tmpSearchResult.AddToListbox(results);safetyCount:+1 + tmpCharCount:+tmpFindPos+tmpStringLength + tmpText = tmpText[tmpFindPos+tmpStringLength..] + tmpFindPos = tmpText.Find(pString) + Wend + EndIf + EndMethod + + Method ShouldContinue() + If safetyCount < 0 Then Return False + If safetyCount >= safetyThreshold Then + If Confirm( LocalizeString("{{search_safetynotification}}").Replace("%1",(safetyResetCount*safetyThreshold)+safetyCount) ) Then + safetyCount = 0 + safetyResetCount:+1 + Else + safetyCount = -1 + Return False + EndIf + EndIf + Return True + EndMethod + + Function Create:TSearchRequester(host:TCodePlay) + Local search:TSearchRequester = New TSearchRequester + search.initrequester(host,"{{search_window_title}}",440,280,STYLE_CANCEL|STYLE_DIVIDER|STYLE_OK|STYLE_STATUS|STYLE_RESIZABLE,strSearchText) + DisableGadget(search.ok) + + SetGadgetLayout(CreateLabel("{{search_label_find}}:",6,8+4,95,24,search.window),EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED,EDGE_CENTERED) + search.findbox=CreateTextField(103,8,ClientWidth(search.window)-(103+6),21,search.window);SetGadgetLayout(search.findbox,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED) + + + SetGadgetLayout(CreateLabel("{{search_label_filetypes}}:",6,42,95,24,search.window),EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED,EDGE_CENTERED) + search.typebox=CreateComboBox(103,38,ClientWidth(search.window)-(103+6),24,search.window);SetGadgetLayout(search.typebox,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED) + + AddGadgetItem( search.typebox, "{{search_type_bmaxfiles}}",GADGETITEM_DEFAULT|GADGETITEM_LOCALIZED,-1,"*.bmx" ) + AddGadgetItem( search.typebox, "{{search_type_codefiles}}",GADGETITEM_LOCALIZED,-1,fileTypes ) + AddGadgetItem( search.typebox, "{{search_type_allfiles}}",GADGETITEM_LOCALIZED,-1,"*") + + SetGadgetLayout(CreateLabel("{{search_label_searchpath}}:",6,72,95,48,search.window),1,0,1,0) + search.pathbox=CreateTextField(103,68,ClientWidth(search.window)-(103+6+30+6),21,search.window);SetGadgetLayout(search.pathbox,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED) + search.pathbutton=CreateButton("..",ClientWidth(search.window)-(34+6),65,34,26,search.window);SetGadgetLayout(search.pathbutton,EDGE_CENTERED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED) + SetGadgetText(search.pathbox, CurrentDir()) + + search.pathsubdir=CreateButton("{{search_btn_searchsubfolders}}",103,98,ClientWidth(search.window)-(103+6),20,search.window,BUTTON_CHECKBOX);SetGadgetLayout(search.pathsubdir,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED) + SetButtonState(search.pathsubdir,True) + + search.results=CreateListBox(6,128,ClientWidth(search.window)-12,280-(128+6),search.window);SetGadgetLayout(search.results,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED) + + Return search + End Function +End Type + + +Type TProjectRequester Extends TRequester + Field projects:TProjects + Field listbox:TGadget + Field add:TGadget + Field remove:TGadget + Field props:TGadget + Field moveup:TGadget + Field movedown:TGadget + Field Current:TProjectFolderNode + + Method Invoke(command,arg:Object=Null) + Select command + Case TOOLACTIVATE + Refresh + End Select + End Method + + Method SetCurrent(i) + If i=-1 + DisableGadget remove + DisableGadget moveup + DisableGadget movedown + DisableGadget props + Current=Null + Else + Current=TProjectFolderNode(GadgetItemExtra(listbox,i)) + If Current + EnableGadget remove + EnableGadget props + EnableGadget moveup + EnableGadget movedown + EndIf + EndIf + End Method + + Method Poll() + Local index + Select EventSource() + Case window + If EventID()=EVENT_WINDOWCLOSE Then Hide() + Case add + If EventID() = EVENT_GADGETACTION Then + projects.NewProject + Refresh + EndIf + Case remove + If EventID() = EVENT_GADGETACTION Then + projects.RemoveProject SelectedGadgetItem(listbox) + Refresh + EndIf + Case cancel + If EventID() = EVENT_GADGETACTION Then Hide + Case props + If EventID() = EVENT_GADGETACTION And Current + host.projectprops.Open(Current) + EndIf + Case listbox + If EventID()=EVENT_GADGETSELECT + SetCurrent SelectedGadgetItem(listbox) 'EventData() + ElseIf EventID()=EVENT_GADGETACTION + SetCurrent SelectedGadgetItem(listbox) + host.projectprops.Open(Current) + EndIf + Case moveup + If EventID()=EVENT_GADGETACTION Then + index=projects.MoveProject(SelectedGadgetItem(listbox),-1) + Refresh + SelectGadgetItem listbox,index + SetCurrent(index) + EndIf + Case movedown + If EventID()=EVENT_GADGETACTION Then + index=projects.MoveProject(SelectedGadgetItem(listbox),1) + Refresh + SelectGadgetItem listbox,index + SetCurrent(index) + EndIf + End Select + End Method + + Method Refresh() + ClearGadgetItems listbox + For Local node:TNode = EachIn projects.kids + If TFolderNode(node)'node.argument + AddGadgetItem listbox,node.name,0,-1,"",node + EndIf + Next + SetCurrent -1 + End Method + + Method Open(projnode:TProjects) + projects=projnode + Refresh + Show + End Method + + Function Create:TProjectRequester(host:TCodePlay) + Local x,y + Local proj:TProjectRequester = New TProjectRequester + + proj.initrequester(host,"{{projman_window_title}}",400,168,STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL) + proj.listbox=CreateListBox( 6,8,244,154,proj.window ) + + x=ClientWidth(proj.window)-144 + proj.add=CreateButton("{{projman_btn_addproj}}",x,8,138,26,proj.window) + proj.remove=CreateButton("{{projman_btn_delproj}}",x,40,138,26,proj.window) + + proj.moveup=CreateButton("{{projman_btn_moveup}}",x,72,138,26,proj.window) + proj.movedown=CreateButton("{{projman_btn_movedn}}",x,104,138,26,proj.window) + + proj.props=CreateButton("{{projman_btn_properties}}",x,136,138,26,proj.window) + + DisableGadget proj.remove + DisableGadget proj.moveup + DisableGadget proj.movedown + DisableGadget proj.props + Return proj + End Function +End Type + +Type TProjectProperties Extends TRequester + Field proj:TProjectFolderNode + Field newproj:Int = False 'If 'True' then cancel/close deletes project. + Field localname:TGadget + Field localpath:TGadget + Field pathbutton:TGadget + Field path:TGadget + Field user:TGadget + Field password:TGadget + Field checkout:TGadget +' Field update:TGadget +' Field commit:TGadget + Field poprequester:TRequester 'hack for restoring to projectmanager requester + Field dirty + + Method Invoke(command,arg:Object=Null) + Select command + Case TOOLACTIVATE + Refresh + End Select + End Method + + Method Tidy() + newproj = False + If dirty + proj.Set GadgetText(localname),GadgetText(localpath),GadgetText(path),GadgetText(user),GadgetText(password) + dirty=False + EndIf + End Method + + Method Poll() + If (EventID() <> EVENT_GADGETACTION) And (EventID() <> EVENT_WINDOWCLOSE) Then Return + Select EventSource() + Case localname,localpath,path,user,password + dirty=True + Case pathbutton + Local dir$=RequestDir(LocalizeString("{{project_requestfolder_title}}")) + If dir + If dir[dir.length-1..]="/" 'fltk hack + dir=dir[..dir.length-1] + EndIf + SetGadgetText localpath,dir + If GadgetText(localname)="" + SetGadgetText localname,StripDir(dir) + EndIf + dirty=True + EndIf + Case checkout + Tidy() + Hide() + proj.CheckoutVersion() +Rem + Case commit + Tidy + Hide + proj.CommitVersion + Case update + Tidy + Hide + proj.UpdateVersion +EndRem + Case ok + Tidy() + Hide() + Case cancel + Hide() + Case window + If EventID()=EVENT_WINDOWCLOSE + Hide() + EndIf + End Select + End Method + + Method Hide() + If proj And newproj Then proj.Free() + EnableGadget host.window + HideGadget window + host.UnhookRequester Self'poprequester + If poprequester poprequester.Show + End Method + + Method Refresh() + SetGadgetText localname,proj.name + SetGadgetText localpath,proj.path + SetGadgetText path,proj.svnpath + SetGadgetText user,proj.svnuser + SetGadgetText password,proj.svnpass + End Method + + Method Open(projnode:TProjectFolderNode, newproject:Int = False) + newproj=newproject + proj=projnode + Refresh() + Show() + End Method + + Function Create:TProjectProperties(host:TCodePlay) + Local proj:TProjectProperties = New TProjectProperties + proj.initrequester(host,"{{project_window_title}}",480,250,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL) + proj.modal = True + + Local projectdetails:TGadget = CreatePanel(6,8,ClientWidth(proj.window)-12,85,proj.window,PANEL_GROUP,"{{project_group_details}}") + + Local i,n,y + y=4 + + CreateLabel("{{project_label_name}}:",6,y+4,72,24,projectdetails) + proj.localname=CreateTextField(88,y,ClientWidth(projectdetails)-(88+6),21,projectdetails) +' proj.pathbutton=CreateButton("..",434,y,34,28,projectdetails) + y:+30 + + CreateLabel("{{project_label_path}}:",8,y+4,72,24,projectdetails) + proj.localpath=CreateTextField(88,y,ClientWidth(projectdetails)-(88+34+6+6),21,projectdetails) + proj.pathbutton=CreateButton("..",ClientWidth(projectdetails)-(34+6),y-3,34,26,projectdetails) + y:+30 + + + Local svnbox:TGadget = CreatePanel(6,101,ClientWidth(proj.window)-12,144,proj.window,PANEL_GROUP,"{{project_group_svn}}") + y=4 + CreateLabel("{{project_label_url}}:",8,y+LABELOFFSET,72,24,svnbox) + proj.path=CreateTextField(88,y,ClientWidth(svnbox)-92,21,svnbox) + y:+30 + CreateLabel("{{project_label_username}}:",8,y+LABELOFFSET,72,24,svnbox) + proj.user=CreateTextField(88,y,ClientWidth(svnbox)-92,21,svnbox) + y:+30 + CreateLabel("{{project_label_password}}:",8,y+LABELOFFSET,72,24,svnbox) + proj.password=CreateTextField(88,y,ClientWidth(svnbox)-92,21,svnbox,TEXTFIELD_PASSWORD) + y:+30 + proj.checkout=CreateButton("{{project_btn_checkout}}",ClientWidth(svnbox)-154,ClientHeight(svnbox)-32,150,28,svnbox) +' proj.update=CreateButton("{{project_btn_update}}",180,y+10,150,28,svnbox) +' proj.commit=CreateButton("{{project_btn_commit}}",340,y+10,150,28,svnbox) + y:+40 + + Return proj + End Function +End Type + +Function GetInfo$(a$ Var) + Local p,r$ + p=a.Find("|")+1 + If p=0 p=a.length+1 + r$=a$[..p-1] + a$=a$[p..] + Return r$ +End Function + +Type TFolderNode Extends TNode + Field owner:TNode + Field path$ + Field scanned + Field version + Field foldertype + + Const PROJECTFOLDER=0 + Const DIRECTORYFOLDER=1 + Const FILEFOLDER=2 + + Method FindFolderFromPath:TFolderNode(dir$) + Local result:TFolderNode + If path=dir Return Self + For Local folder:TFolderNode = EachIn kids + result=folder.FindFolderFromPath(dir) + If result Return result + Next + End Method + + Method SetName(n$) + If version Then n:+"("+version+")" + Super.SetName( n ) + Refresh + End Method + + Method SetVersion(ver) + version=ver + SetName StripDir(path) + End Method + + Method Write(stream:TStream) + Local isopen + If GetState()=OPENSTATE isopen=True + If version Or isopen + stream.WriteLine "proj_data="+path+"|"+isopen+"|"+version+"|" + EndIf + For Local folder:TFolderNode = EachIn kids + folder.Write(stream) + Next + End Method + + Method ProjectHost:TCodePlay() + Local n:TNode = Self + While n + If TProjects(n) Return TProjects(n).host + n=n.parent + Wend + End Method + + Method ProjectNode:TProjectFolderNode() + Local n:TNode = Self + While n + If TProjectFolderNode(n) Return TProjectFolderNode(n) + n=n.parent + Wend + End Method + + Method RunSVN(cmd$,about$,refresh) + + Local host:TCodePlay = ProjectHost() + If Not host Notify LocalizeString("{{svn_notification_nodehostnotfound}}");Return + + Local project:TProjectFolderNode = ProjectNode() + If Not project Notify LocalizeString("{{svn_notification_nodeprojectnotfound}}");Return + + If project.svnuser + cmd:+" --username "+project.svnuser + If project.svnpass cmd:+" --password "+project.svnpass + EndIf + + If refresh + host.execute cmd,about,MENUREFRESH,True,Self + Else + host.execute cmd,about,0,0,Self + EndIf + End Method + + Method UpdateVersion() + Local cmd$=svncmd+" update" + cmd:+" "+quote(path) + RunSVN cmd,LocalizeString("{{svn_msg_updating}}").Replace("%1",path),True + End Method + + Method CommitVersion() + Local cmd$=svncmd+" commit" + cmd:+" -m ~qmy comment~q" + cmd:+" "+quote(path) + RunSVN cmd,LocalizeString("{{svn_msg_committing}}").Replace("%1",path),False + End Method + + Method Open(view=-1) + Update(True) + Super.Open view + End Method + + Method AddFileNode:TNode(file$) + Local n:TNode + Local ext$ + If (","+FileTypes+",").Contains(","+ExtractExt(file).toLower()+",") Then + n=AddNode(StripDir(file)) + n.SetAction(owner,TOOLOPEN,file) + ext=ExtractExt(file$).ToLower() + n.sortname=ext+n.name + Return n + EndIf + End Method + + Method AddFolderNode:TNode(path$) + Local n:TFolderNode = TFolderNode.CreateFolderNode(path,DIRECTORYFOLDER) + n.owner = owner + n.sortname=" "+n.name + Append n + Return n + End Method + + Method Scan(o:TNode) + Local p$ + Local flist:TList = New TList + + owner=o + + For Local f$ = EachIn LoadDir(path,True) + If f[..1] = "." Then Continue + p$=path+"/"+f + Select FileType(p$) + Case FILETYPE_FILE + AddFileNode p$ + Case FILETYPE_DIR + AddFolderNode p$ + End Select + Next + + SortKids + scanned = True + + End Method + + Method ScanKids() + For Local f:TFolderNode = EachIn kids + f.owner = owner + f.Update(False) + Next + End Method + + Method Rescan() + scanned = False + Update() + EndMethod + + Method Update( alwaysScanKids:Int = False ) + If Not scanned Then + FreeKids() + Scan owner + EndIf + If alwaysScanKids Or Not IsHidden() Then ScanKids() + Refresh() + End Method + + Method Invoke(command,argument:Object=Null) + Local host:TCodePlay + Local cmd,p + Local line$ + + host=ProjectHost() + If Not host Notify LocalizeString("{{svn_notification_nodehostnotfound}}");Return + + Select command + Case TOOLOUTPUT + line$=String(argument) + p=line.find(" revision ") + If p>-1 + SetVersion Int(line[p+10..]) + EndIf +' If line[..12]="At revision " +' DebugLog "TOOLOUTPUT:"+line + Return + Case TOOLERROR + line$=String(argument) +' DebugLog "TOOLERROR:"+line + Return + Case TOOLMENU + cmd=Int(String(argument)) + Select cmd + Case 0 'special toolmenu-command=0 fired by rightbutton node context + Highlight + Local menu:TGadget + menu=host.projects.projmenu + PopupWindowMenu host.window,menu,Self + Case MENUREFRESH + Rescan() + Case MENUBROWSE + OpenURL RealPath(path) + Case MENUSHELL + Local cd$=CurrentDir() + ChangeDir RealPath(path) +?MacOS + host.execute "/bin/bash","Shell Terminal" +?Linux + host.execute "/bin/bash","Shell Terminal" +?Win32 + host.execute "cmd","Shell Terminal - Type Exit To End" +? + ChangeDir cd + Case MENUUPDATE + UpdateVersion + Case MENUCOMMIT + CommitVersion +' Case MENUPROPS +' host.projectprops.Open(Self) + Case MENUFINDINFILES + host.searchreq.ShowWithPath( RealPath(path) ) + End Select + End Select + End Method + + Function CreateFolderNode:TFolderNode(path$,foldertype) + Local n:TFolderNode = New TFolderNode +' n.host=host + n.SetName( StripDir(path) ) + n.path = path + n.foldertype = foldertype + Return n + End Function +End Type + +Type TProjectFolderNode Extends TFolderNode + + Field owner:TProjects + Field svnpath$,svnuser$,svnpass$,svnversion + Field svnerr$ + + Method CheckoutVersion() 'to do - needs to move old version to temp? + Local cmd$ = svncmd+" checkout" + cmd:+" "+quote(svnpath) + cmd:+" "+quote(path) + RunSVN cmd,LocalizeString("{{svn_msg_checkingout}}").Replace("%1",svnpath).Replace("%2",path),True + End Method + + Function Crypt$(a$) + Local b$,c + For Local i:Int = 0 Until a.length + c=a[i] + If c>31 c:~((i*-5)&31) + b:+Chr(c&255) + Next + Return b + End Function + + Method ToString$() + Local prj$ + Local isopen + If GetState()&OPENSTATE isopen=True + prj=name+"|"+path+"|"+svnpath+"|"+svnuser+"|"+crypt(svnpass)+"|"+isopen+"|"+version + Return prj + End Method + + Method Write(stream:TStream) + stream.WriteLine "proj_node="+ToString() + For Local folder:TFolderNode = EachIn kids + folder.Write(stream) + Next + End Method + + Method FromString(info$) + Local n$ = GetInfo(info) + If Not n Then n = "Unknown" + SetName( n ) + path=GetInfo(info) + If path path=owner.host.FullPath(path) + svnpath=GetInfo(info) + svnuser=GetInfo(info) + svnpass=GetInfo(info) + Scan(owner) + Local isopen,vers + isopen=Int(GetInfo(info)) + If isopen + Open + EndIf + vers=Int(GetInfo(info)) + If vers + SetVersion vers + EndIf + End Method + + Method Invoke(command,argument:Object=Null) + Local cmd + Select command + Case TOOLMENU + cmd=Int(String(argument)) + Select cmd + Case MENUPROPS + Return owner.host.projectprops.Open(Self) + End Select + End Select + Return Super.Invoke(command,argument) + End Method + + Method Set(n$,p$,s$,user$,pass$) + path=owner.host.FullPath(p) + setname n + svnpath=s + svnuser=user + svnpass=pass + Rescan() + owner.host.projectreq.Refresh() + End Method + + Function CreateProjectNode:TProjectFolderNode(projects:TProjects,info$) + Local n:TProjectFolderNode = New TProjectFolderNode + n.owner=projects + n.FromString(info) + n.foldertype=PROJECTFOLDER + Return n + End Function +End Type + +Type TProjects Extends TNode + Field host:TCodePlay + Field addproj:TNode + Field projmenu:TGadget + Field projmenuprops:TGadget + + Method RemoveProject(index) + Local node:TNode + If index<0 Or index>=kids.Count() Return + node=TNode(kids.ValueAtIndex(index)) + If node node.Free + Refresh + End Method + + Method MoveProject(index,dir) + Local node:TNode + Local link:TLink + If index<0 Or index>=kids.Count() Return index + node=TNode(kids.ValueAtIndex(index)) + If node + addproj.Detach + node.Hide + link=kids.FindLink(node) + If dir>0 + If link link=link._succ + If link + kids.Remove node + kids.InsertAfterLink node,link + index:+1 + EndIf + Else + If link link=link._pred + If link + kids.Remove node + kids.InsertBeforeLink node,link + index:-1 + EndIf + EndIf + Append addproj + Refresh + EndIf + Return index + End Method + + Method NewProject() + addproj.Detach + Local proj:TProjectFolderNode = TProjectFolderNode.CreateProjectNode(Self,LocalizeString("{{project_defaultname}}")) +' proj.scan(Self) + Append proj + Append addproj + host.projectprops.Open(proj, True) + Refresh + End Method + + Method AddProject(data:TList) + Local project:TProjectFolderNode + Local folder:TFolderNode + For Local info$ = EachIn data + If Not project + addproj.Detach + project=TProjectFolderNode.CreateProjectNode(Self,info) + Append project + Append addproj + Refresh + Else + Local path$ + Local popen + Local pversion + path=GetInfo(info) + popen=Int(GetInfo(info)) + pversion=Int(GetInfo(info)) + folder=project.FindFolderFromPath(path) + If folder + folder.SetVersion pversion + folder.ReScan() + If popen Then folder.Open() + EndIf + EndIf + Next + End Method + + Method Write(stream:TStream) + For Local project:TProjectFolderNode = EachIn kids + project.Write(stream) + Next + End Method + + Method Invoke(command,argument:Object=Null) + Select command + Case TOOLNEW + NewProject + Case TOOLOPEN + host.OpenSource String(argument) + End Select + End Method + + Function CreateProjects:TProjects(host:TCodePlay) + Local p:TProjects = New TProjects + p.SetName("{{navnode_projects}}") + p.host=host + p.addproj=p.AddNode("{{navnode_addproject}}") + p.addproj.SetAction p,TOOLNEW + + p.projmenu=CreateMenu("{{popup_nav_proj}}",0,Null) + CreateMenu "{{popup_nav_proj_refresh}}",MENUREFRESH,p.projmenu + CreateMenu "{{popup_nav_proj_findinfiles}}",MENUFINDINFILES,p.projmenu + CreateMenu "{{popup_nav_proj_explore}}",MENUBROWSE,p.projmenu + CreateMenu "{{popup_nav_proj_shell}}",MENUSHELL,p.projmenu + CreateMenu "",0,p.projmenu + CreateMenu "{{popup_nav_proj_svnupdate}}",MENUUPDATE,p.projmenu + CreateMenu "{{popup_nav_proj_svncommit}}",MENUCOMMIT,p.projmenu + CreateMenu "",0,p.projmenu + p.projmenuprops=CreateMenu("{{popup_nav_proj_properties}}",MENUPROPS,p.projmenu) + host.projectreq.projects=p + Return p + End Function +End Type + +Type TByteBuffer Extends TStream + Field bytes:Byte[] + Field readpointer + + Method Read( buf:Byte Ptr,count ) + If count>readpointer count=readpointer + If Not count Return + MemCopy buf,bytes,count + readpointer:-count + If readpointer MemMove bytes,Varptr bytes[count],readpointer + Return count + End Method + + Method ReadLine$() + For Local i:Int = 0 Until readpointer + If bytes[i]=10 Or bytes[i] = 0 Then + Local tmpBytes:Byte[] = New Byte[i+1] + If i And bytes[i-1] = 13 Then i:-1 + Read(tmpBytes,tmpBytes.length) + Return String.FromBytes(tmpBytes, i) + EndIf + Next + EndMethod + + Method WriteFromPipe( pipe:TPipeStream ) + Local n,m,count = pipe.ReadAvail() + n=readpointer+count + If n>bytes.length + m=Max(bytes.length*1.5,n) + bytes=bytes[..m] + EndIf + pipe.Read( Varptr bytes[readpointer], count ) + readpointer=n + Return count + EndMethod + + Method Write( buf:Byte Ptr,count ) + Local n,m + n=readpointer+count + If n>bytes.length + m=Max(bytes.length*1.5,n) + bytes=bytes[..m] + EndIf + MemCopy Varptr bytes[readpointer],buf,count + readpointer=n + Return count + End Method + + Method LineAvail() + For Local i:Int = 0 Until readpointer + If bytes[i]=10 Return True + Next + End Method + + Method FlushBytes:Byte[]() + Local res:Byte[] = bytes[..readpointer] + readpointer = 0 + Return res + End Method +End Type + +Type TObj + Field addr$,sync,refs,syncnext + Method ShouldSync( pDebugTree:TDebugTree ) + If sync < pDebugTree.sync Then pDebugTree.QueueSync( Self ) + EndMethod + Method HasSynced( pSync% ) + sync = pSync;syncnext = False + EndMethod +End Type + +Type TVar Extends TNode + + Field owner:TDebugTree + Field obj:Object + + Method Free() + If TObj(obj) owner.RemoveObj TObj(obj) + obj=Null + Super.Free() + End Method + + Method SetVarName(n$) + Local p + name=n +' if object ref set addr$ field + If name.find("$=")=-1 And name.find( ":String=" )=-1 And name.find(")=$")=-1 + p=name.find("=$") + If p<>-1 + If TObj(obj) Then + If TObj(obj).addr <> name[p+2..] Then + TDebugTree.RemoveObj TObj(obj) + Else + TObj(obj).refs:-1 + EndIf + EndIf + obj=TDebugTree.AddObj(name[p+2..]) + 'Request object dump if we are visible now that + 'we have updated our own object pointer. + If Not IsHidden() Then Request() + Return + EndIf + p=name.find("=Null") + If p<>-1 + FreeKids + TDebugTree.RemoveObj TObj(obj) + obj=Null + EndIf + EndIf + End Method + + Method AddVar(name$) + Local v:TVar=New TVar + v.owner=owner + Append v + v.setvarname name + End Method + + Method SetValue(val:TVar) + Local v:TVar,w:TVar,i,kidsarray:Object[] +' if this is a reference to same object refresh values + If obj And obj=val.obj + If kids.IsEmpty() + For v=EachIn val.kids + AddVar v.name + Next + Else + kidsarray = kids.ToArray() + For v=EachIn val.kids + If i")+1 + Local r=f.Find(",")+1 + If p And q And r + file=f[..p-1] + line=Int(f[p..r-1]) + column=Int(f[r..q-1]) + EndIf + obj=Self + End Method + + Method Request() + For Local kid:TVar = EachIn kids + kid.Request() + Next + EndMethod + +End Type + +Type TDebugTree Extends TVar + Global sync + Global objmap:TMap = CreateMap() + Field host:TCodePlay + Field instack:TList + Field inscope:TScope + Field invar:TVar + Field infile$ + Field inexception$ + Field firststop + Field cancontinue + + Method Reset() +' host.SetMode host.DEBUGMODE + SetStack( New TList ) + ClearMap objmap + instack=Null + inscope=Null + invar=Null + infile="" + inexception="" + sync=0 + firststop=True + cancontinue=False + End Method + + Function AddObj:TObj(addr$) + Local o:TObj = TObj(MapValueForKey( objmap, addr )) + If o Then + o.refs:+1 + Else + o=New TObj + o.addr=addr + o.refs=1 + MapInsert objmap, addr, o + EndIf + Return o + End Function + + Function FindObj:TObj(addr$) + Return TObj(MapValueForKey( objmap, addr )) + End Function + + Function RemoveObj(obj:TObj) ':TObj + If obj Then + obj.refs:-1 + If Not obj.refs Then MapRemove objmap, obj.addr + EndIf + End Function + + Method SyncVars() + sync:+1 + For Local tmpVar:TVar = EachIn kids + tmpVar.Request() + Next + End Method + + Method QueueSync( pObj:TObj ) + If Not pObj Then Return + 'Sync as soon as the debug pipe is clear + '(see TOuputPanel.SendDumpRequests()). + pObj.syncnext = True + EndMethod + + Method SetStack(list:TList) + Local openscope:TScope + Local s:TScope + Local count,i + + count=kids.count() 'root.varlist.count() + For Local scope:TScope = EachIn list + If i>=count + Append scope 'root.Append scope + s=scope + Else + s=TScope(kids.ValueAtIndex(i)) +' simon was here + If s.name=scope.name + s.SetScope scope + scope.Free + Else + While kids.count()>i + s=TScope(kids.Last()) + s.free + Wend + Append scope + s=scope + count=i+1 + EndIf + + EndIf + If firststop + If host.IsSourceOpen(s.file) openscope=s + Else + openscope=s + EndIf + i:+1 + Next + While kids.count()>i + s=TScope(kids.Last()) + s.free + Wend + If list.IsEmpty() Return + If Not openscope openscope=TScope(list.First()) + If openscope SelectScope openscope,True + Refresh + firststop=False + End Method + + Method SelectScope(scope:TScope,open) + If Not scope Return + host.SetMode host.DEBUGMODE ' simon was here, smoved from reset + If scope.file host.DebugSource scope.file,scope.line,scope.column + scope.Open() +' If open +' SelectTreeViewNode scope.node +' scope.open +' EndIf + End Method + + Method ProcessError$(line$) + Local p + + While p < line.length + If line[p]=$3E Then p:+1 Else Exit '">" + Wend + + If p = line.length Return + If p Then line = line[p..] + + If Not line.StartsWith("~~>") Return line + line=line[2..] + + If invar + If line="}" + SetValue invar 'root + invar.Free + invar=Null + Else +' If Not invar.name +' invar.name=line +' Else + invar.AddVar line +' EndIf + EndIf + Return + EndIf + + If instack + If line="}" + + SetStack instack + instack=Null + inscope=Null + 'Request first object dumps, and bump sync count + SyncVars + If inexception + Notify inexception + inexception="" + EndIf + Return + EndIf + + If infile + If line="Local " + Else + inscope=New TScope +' Print "inscope.line="+line + inscope.name=line + inscope.owner=Self + instack.AddLast inscope + EndIf + If inscope inscope.setfile Self,infile + infile="" + Return + EndIf + + If line.StartsWith("@") And line.Contains("<") + infile=line[1..] + Else + If inscope inscope.AddVar line + EndIf + + Return + EndIf + + If line.StartsWith("Unhandled Exception:") + inexception=line + host.output.WritePipe "t" + cancontinue=False + Return + EndIf + + If line="StackTrace{" + instack=New TList + Return + EndIf + + If line="Debug:" Or line="DebugStop:" + host.output.WritePipe "t" + If Not cancontinue Then + cancontinue=True + host.RefreshToolbar() + EndIf + Return + EndIf + + If line.StartsWith("ObjectDump@") + p=line.find("{",11) + If p=-1 Return line + line=line[11..p] + invar=New TVar + invar.obj=FindObj(line) + invar.owner=Self + Return + EndIf + + End Method + + Function CreateDebugTree:TDebugTree(host:TCodePlay) + Local d:TDebugTree = New TDebugTree + d.owner=d + d.SetName "{{navtab_debug}}" + d.host=host + d.Open + Return d + End Function +End Type + +Type TNodeView + Field owner:TNavBar + Field root:TNode + Field treeview:TGadget + Field index + + Method NewView() + Local n:TNode,hnode:TGadget + hnode=SelectedTreeViewNode(treeview) + n=root.Find(hnode,index) + If n And n.parent owner.AddView n + End Method + + Method OnEvent() + Local n:TNode = root.Find(TGadget(EventExtra()),index) + If Not n Return 'probably an eventgadgetselect -1 Notify("could not find in root");Return + + Select EventID() + Case EVENT_GADGETSELECT + n.invoke(TOOLSELECT) + Case EVENT_GADGETACTION + n.invoke(TOOLACTIVATE) + Case EVENT_GADGETMENU + n.invoke(TOOLMENU,Self) + Case EVENT_GADGETOPEN + n.open index + Case EVENT_GADGETCLOSE + n.close index + End Select + End Method +End Type + +Type TNavBar Extends TEventHandler + Field host:TCodePlay + Field tabber:TGadget + Field viewlist:TList=New TList + Field selected:TNodeView + Field navmenu:TGadget + + Method SelectedView() + If selected Return selected.index + End Method + + Method SelectView(index) + Local n:TNodeView + If index>=viewlist.count() Return + n=TNodeView(viewlist.ValueAtIndex(index)) + If Not n Print "selectview failed";Return + If n<>selected + If selected HideGadget selected.treeview + selected=n + EndIf + ShowGadget n.treeview + SelectGadgetItem tabber,index + End Method + + Method AddView(node:TNode) + Local n:TNodeView + Local index,root:TGadget + For n=EachIn viewlist + If n.root=node SelectView n.index;Return + Next + n=New TNodeView + n.owner=Self + n.root=node + n.treeview=CreateTreeView(0,0,ClientWidth(tabber),ClientHeight(tabber),tabber) + host.options.navstyle.Apply n.treeview + SetGadgetLayout n.treeview,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED + HideGadget n.treeview + + n.index=viewlist.Count() + viewlist.AddLast n + + AddGadgetItem tabber,node.name,GADGETITEM_LOCALIZED + root=TreeViewRoot(n.treeview) + node.setnode root,n.index + SelectView n.index + Return n.index + End Method + + Method OnEvent() + If EventSource()=tabber + SelectView SelectedGadgetItem(tabber) + End If + If selected And EventSource()=selected.treeview + selected.OnEvent + EndIf + End Method + + Method Refresh() + For Local view:TNodeView = EachIn viewlist + host.options.navstyle.Apply view.treeview + Next + End Method + + Method Invoke(command,argument:Object=Null) + If command=TOOLREFRESH Refresh() + If command=TOOLNEWVIEW And selected selected.NewView + End Method + + Function CreateNavMenu:TGadget() + Local edit:TGadget = CreateMenu("&Nav",0,Null) + CreateMenu "&New View",MENUNEWVIEW,edit + Return edit + End Function + + Function Create:TNavBar(host:TCodePlay, parent:TGadget) ',root:TNode) + Local n:TNavBar = New TNavBar + n.host=host + n.tabber=CreateTabber(0,0,ClientWidth(parent),ClientHeight(parent),parent) + SetGadgetLayout(n.tabber,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED) +' n.AddView root + n.navmenu=CreateNavMenu() + Return n + End Function + +End Type + +Type TOutputPanel Extends TToolPanel 'used build and run + + Field host:TCodePlay + Field output:TGadget + + Field process:TProcess + Field pipe:TStream + + Field wpipe:TTextStream + + Field user$,cmdline$,err$,post$ + Field errbuffer:TByteBuffer + Field outputmenu:TGadget + Field posttool:TTool + + Method ClearDumpRequests() + For Local o:TObj = EachIn MapValues(host.debugtree.objmap) + o.HasSynced(o.sync) + Next + EndMethod + + Method SendDumpRequests() + For Local o:TObj = EachIn MapValues(host.debugtree.objmap) + If o.syncnext Then + If o.addr <> "00000000" Then WritePipe "d"+o.addr + o.HasSynced( host.debugtree.sync ) + EndIf + Next + EndMethod + + Method Clear() + If Not output Open() + SetGadgetText output,"" + End Method + + Method WriteAscii(mess$) + If Not output Open() + AddTextAreaText output,mess.Replace("~0","") + End Method + + Method Write(mess$) + If Not output Open() + AddTextAreaText output,mess.Replace("~0","") + End Method + + Method Execute(cmd$,mess$="",exe$="",home=True,owner:TTool=Null) + If Not output Open() + If Not mess$ mess$=cmd$ + err$="" + post$=exe + posttool=owner + host.SelectPanel Self + host.debugtree.Reset + + If process And ProcessStatus(process) + Delay 500 + If ProcessStatus(process) + Notify LocalizeString("{{output_notification_stillbusy}}").Replace("%1",cmdline) + Return + EndIf + EndIf + cmd=cmd.Trim() + process=CreateProcess(cmd$,HIDECONSOLE) + If Not process Then Notify LocalizeString("{{output_notification_processfailure}}").Replace("%1",cmd);Return + If Not process.status() Then Notify LocalizeString("{{output_notification_failedstart}}").Replace("%1",cmd);process=Null;Return + pipe=Process.pipe + wpipe=TTextStream.Create(pipe,TTextStream.UTF8) + + cmdline=cmd + If home Clear + Write( mess+"~n" ) + errbuffer = New TByteBuffer + host.RefreshToolbar + + End Method + + Method WritePipe(l$) + Try + If pipe pipe.WriteLine(l) + Catch ex:TStreamWriteException + Write LocalizeString("{{output_msg_debugfailure}}~n").Replace("%1",l) + Stop + EndTry + End Method + + Method Go() + WritePipe "r" + host.debugtree.cancontinue = False + host.SelectPanel Self + host.RefreshToolbar() + End Method + + Method StepOver() + ClearDumpRequests() + WritePipe "s" + End Method + + Method StepIn() + ClearDumpRequests() + WritePipe "e" + End Method + + Method StepOut() + ClearDumpRequests() + WritePipe "l" + End Method + + Method Stop() + If Not process Return + process.Terminate() + FlushPipes process.pipe,process.err + process.Close() + process=Null + Write LocalizeString("~n{{output_msg_processterminated}}~n") + host.DebugExit() + Close() + End Method + + Method Wait() + While process And process.status() + PollSystem + Wend + End Method + + Method Invoke(command,argument:Object=Null) + Select command + Case TOOLSHOW + host.SetTitle() + If output ActivateGadget output + Case TOOLCLOSE + host.RemovePanel Self + output=Null + Case TOOLCUT + GadgetCut output + Case TOOLCOPY + GadgetCopy output + Case TOOLPASTE + GadgetPaste output + Case TOOLSELECTALL + If output SelectTextAreaText output + Case TOOLREFRESH + host.options.outputstyle.apply output + End Select + End Method + + Method Close() + host.SelectPanel host.activepanel + End Method + + Method Escape() + Stop + Close + End Method + + Function outputfilter(event:TEvent,context:Object) + Local out:TOutputPanel=TOutputPanel(context) + If Not out Return + Select event.id + Case EVENT_KEYDOWN + If event.data=27 + out.Escape() + Return 0 + EndIf + Case EVENT_KEYCHAR +' Print "output_keychar "+event.data + out.writechar(event.data) + End Select + Return 1 + End Function + + Method OnEvent() + If EventSource()=output + If EventID()=EVENT_GADGETMENU + PopupWindowMenu host.window,outputmenu + EndIf + EndIf +' Case EVENT_TIMERTICK + If Not process Return + + ReadPipes process.pipe,process.err + + If Not process.status() + process.terminate + FlushPipes process.pipe,process.err + process.close() + process = Null + Write LocalizeString("~n{{output_msg_processcomplete}}~n") + host.DebugExit + host.SelectPanel Self + + If err + host.ParseError err + Else + If post$ + Local menuaction=Int(post) + If menuaction + host.OnMenu menuaction,posttool +' Else +' Execute post$,"","",False,0 + EndIf + Else + If host.options.hideoutput Close() + EndIf + EndIf + EndIf + + End Method + + Method FlushPipes(pipe:TPipeStream,errpipe:TPipeStream) + ReadPipes(pipe,errpipe) + Local bytes:Byte[] = errbuffer.flushbytes() + If bytes + Local line$=String.FromBytes(bytes,Len bytes) + line=line.Replace(Chr(13),"") + If line<>">" Write line + EndIf + End Method + + Method ReadPipes(pipe:TPipeStream,errpipe:TPipeStream) + Local status + Local bytes:Byte[],line$ + + bytes=pipe.ReadPipe() + If bytes + line$=String.FromBytes(bytes,Len bytes) + line=line.Replace(Chr(13),"") + Write line + EndIf + + If errpipe.ReadAvail() Then + errbuffer.WriteFromPipe(errpipe) + Else + SendDumpRequests() + EndIf + +' If bytes Write String.FromBytes(bytes,bytes.length) + While errbuffer.LineAvail() + line$=errbuffer.ReadLine() + line=host.debugtree.ProcessError(line) + If line + Write line+"~n" + err:+line+"~n" + EndIf + Wend + + End Method + + Method WriteChar(char) + Local pipe:TPipeStream + + If Not process Return + pipe=process.pipe + If char=3 'CTRL-C + Stop() + EndIf + If char=13 'ENTER +' Write Chr(10) + pipe.WriteLine user$ + user="" + EndIf + If char=8 And user.length 'DELETE +' Local pos=TextAreaLen(output) +' If pos SetTextAreaText output,"",pos-1,1,TEXTAREA_CHARS + user=user[..user.length-1] + EndIf + If char>31 +' Write Chr(char) + user:+Chr(char) + EndIf + End Method + + Method Open() + If output Then + codeplay.SelectPanel Self + Return + EndIf + codeplay.addpanel(Self) + output=CreateTextArea(0,0,ClientWidth(panel),ClientHeight(panel),panel,TEXTAREA_WORDWRAP) + DelocalizeGadget output + SetGadgetLayout output,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED + SetGadgetFilter output,outputfilter,Self + SetGadgetText output," " 'simon was here + host.options.outputstyle.apply output + End Method + + Function CreateOutputMenu:TGadget() + Local edit:TGadget = CreateMenu("{{popup_output}}",0,Null) + CreateMenu "{{popup_output_cut}}",MENUCUT,edit + CreateMenu "{{popup_output_copy}}",MENUCOPY,edit + CreateMenu "{{popup_output_paste}}",MENUPASTE,edit + CreateMenu "",0,edit + CreateMenu "{{popup_output_stop}}",MENUSTOP,edit + Return edit + End Function + + Function Create:TOutputPanel(host:TCodePlay) + Local o:TOutputPanel = New TOutputPanel + o.host=host + o.name="{{tab_output}}" + o.outputmenu=CreateOutputMenu() +' o.Open + Return o + End Function + +End Type + +Type TCodeNode Extends TNode + Field owner:TOpenCode + Field pos,count + 'Field groups:TMap=New TMap + + Method Invoke(command,argument:Object=Null) + Select command + Case TOOLACTIVATE + owner.ShowPos(pos) + End Select + End Method + + Method Sync(snap:TNode) + If snap.name<>name SetName(snap.name) + Local n:TCodeNode = TCodeNode(snap) + If n pos=n.pos;count=n.count + Super.Sync(snap) + End Method + + Method SetName(n$) + Local p = n.find("'") + If p<>-1 n=n[..p] + name=n.Trim() +' If owner.host.options.sortcode + sortname=n + End Method + + Method Free() + owner = Null + Super.Free() + End Method + + Method AddCodeNode:TCodeNode(n$,p0,p1) + + Local t$ + Local i:Int = n.find(" ") 'if space then group + + If i>0 + t=n[..i] + n=n[i+1..] +Rem + p=TNode(groups.ValueForKey(t)) + If Not p + p=AddNode(t+"s") + p.Open + groups.insert t,p + EndIf +EndRem + EndIf + + Local c:TCodeNode = New TCodeNode + c.owner=owner + c.setname n$ + c.pos=p0 + c.count=p1-p0 + Append(c) + + Return c + + End Method +End Type + +Type TDiff + Field pos,count,del$,add$,pos0,count0,pos1,textchange = True +End Type + +Type TOpenCode Extends TToolPanel + + Global msgHighlightingStatus$ = "Highlighting" + + Field host:TCodePlay + Field textarea:TGadget + Field dirty=True + Field filesrc$,cleansrc$,cleansrcl$ + Field Current:TDiff + Field undolist:TList=New TList + Field redolist:TList=New TList + Field helpcmd$,helpstring$ + Field seek$ + Field cursorpos,cursorlen,cursorline + Field oldpos,oldlen + Field isbmx,isc,iscpp,ishtml + Field deferpos = -1 + Field tidyqueue1 = -1, tidyqueue2 = -1 + Field editmenu:TGadget + Field codenode:TCodeNode + Field dirtynode,uc + + Function RefreshHighlightingMsg() + msgHighlightingStatus = LocalizeString("{{msg_highlightingcode}}") + EndFunction + + Function IsNotAlpha(c) + If c<48 Return True + If c>=58 And c<65 Return True + If c>=91 And c<95 Return True + If c>=96 And c<97 Return True + If c>=123 Return True + End Function + + Function WordAtPos$(a$,p) + Local c,q,r,n + ' string literal + q=a.findlast(EOL$,a.length-p) + If q=-1 q=0 + For q=q To p-1 + If a[q]=34 Then + n=Not n + r=q + EndIf + Next + If n + q=a.Find("~q",r+1)+1 + If q=0 q=a.length + Return a[r..q] + EndIf + ' alphanumeric + p=Min(p,a.length-1) 'simon was here - crash when checking at last char + For p=p Until 0 Step -1 'simon was here unto->to + If IsNotAlpha(a$[p]) Continue + Exit + Next + For q=p-1 To 0 Step -1 + If IsNotAlpha(a$[q]) Exit + Next + For r=p To a.length-1 + If IsNotAlpha(a$[r]) Exit + Next + Return a[q+1..r] + End Function + + Function FirstDiff(s0$,s1$) + Local n = Min(s0.length,s1.length) + For Local i:Int = 0 Until n + If s0[i]<>s1[i] Return i + Next + Return n + End Function + + Function LastDiff(s0$,s1$) + Local n = Min(s0.length,s1.length) + Local i = s0.length-1 + Local j = s1.length-1 + While n>0 + If s0[i]<>s1[j] Exit + i:-1;j:-1;n:-1 + Wend + Return i+1 + End Function + + Method parsebmx(n:TCodeNode) + Local src$,line,col + Local p,p1,r,t,m,f,l,e + + src=cleansrcl + p1=src.length + p=-1;r=-1;t=-1;m=-1;f=-1;l=-1 + While pn.pos+n.count) + If Not TCodeNode(n.parent) + If n.parent.parent + n = TCodeNode(n.parent.parent) + Else + n = Null + EndIf + Else + n=TCodeNode(n.parent) + EndIf + Wend + If t= ClientWidth(textarea) ) Then + SelectTextAreaText textarea,line,1,TEXTAREA_LINES + Else + SelectTextAreaText textarea,tmpCharLineStart,tmpLine.length-i,TEXTAREA_CHARS + EndIf + EndMethod + + Method ShowPos(pos) + host.SelectPanel( Self ) + HighlightLine( TextAreaLine(textarea,pos) ) + UpdateCursor() + ActivateGadget( textarea ) + End Method + + Method Debug(line,column) + HighlightLine( line-1 ) + UpdateCursor() + End Method + + Method Edit() + SelectTextAreaText( textarea,cursorpos,0,TEXTAREA_CHARS ) + ActivateGadget( textarea ) + UpdateStatus() + End Method + + Method UpdateStatus() + Local c = cursorpos+cursorlen + If cursorline Then c:-TextAreaChar(textarea,cursorline-1) + host.SetStatus helpstring+"~t~t"+LocalizeString("{{status_line_char}}").Replace("%1",cursorline).Replace("%2",(c+1)) + End Method + + Method UpdateCursor() + oldpos=cursorpos + oldlen=cursorlen + cursorpos=TextAreaCursor(textarea,TEXTAREA_CHARS) + cursorlen=TextAreaSelLen(textarea,TEXTAREA_CHARS) + If cursorpos<>oldpos Or cursorlen<>oldlen + Local l = TextAreaLine(textarea,cursorpos)+1 + If l<>cursorline And dirtynode + GetNode().Refresh + dirtynode=False + If (deferpos>=0) UpdateCode 'SetCode cleansrc + EndIf + cursorline=l + UpdateStatus() + BracketMatching(cleansrcl) + If (tidyqueue1 >= 0 Or tidyqueue2 >= 0) Then UpdateCode() + PollSystem + EndIf + End Method + +' tdiff - pos del$ add$ + + Method CalcDiff:TDiff(src$) + Local d:TDiff + If src.length<>cleansrc.length + d=New TDiff + d.pos0=cursorpos + d.count0=cursorlen + d.pos=oldpos + d.count=oldlen + If cursorlen And oldlen 'block modified + d.del=cleansrc[oldpos..oldpos+oldlen] + d.add=src[oldpos..cursorpos+cursorlen] + d.pos1=oldpos + Else + If cursorpos<=oldpos And cursorlen<=oldlen 'backspace + d.del=cleansrc[cursorpos..cursorpos+cleansrc.length-src.length] + d.pos1=cursorpos + Else 'insert + d.del=cleansrc[oldpos..oldpos+oldlen] + d.add=src[oldpos..cursorpos+cursorlen] + d.pos1=oldpos + EndIf + EndIf + Else + If cursorpos>oldpos 'overwrite + d=New TDiff + d.pos0=cursorpos + d.count0=cursorlen + d.pos=oldpos + d.count=oldlen + d.del=cleansrc[oldpos..cursorpos] + d.add=src[oldpos..cursorpos] + d.pos1=oldpos + If d.del = d.add Then d.textchange=False + EndIf + EndIf + Return d + End Method + + Method UpdateCode(makeundo=True) + Local cpos + Local src$ = TextAreaText(textarea) + Local d:TDiff = CalcDiff(src) + If d + If makeundo And d.textchange + undolist.AddLast d + redolist.Clear + EndIf + SetCode src,d + If d.textchange Then dirtynode=True + EndIf + If (deferpos >= 0) Or (tidyqueue1 >= 0) Or (tidyqueue2 >= 0) Then SetCode src + End Method + + Method Undo() + Local d:TDiff + If undolist.IsEmpty() Return + d=TDiff(undolist.RemoveLast()) + redolist.AddLast d + SetTextAreaText textarea,d.del,d.pos1,d.add.length + SelectTextAreaText(textarea,d.pos,d.count) + SetCode TextAreaText(textarea),d + UpdateCursor + End Method + + Method Redo() + Local d:TDiff + If redolist.IsEmpty() Return + d=TDiff(redolist.RemoveLast()) + undolist.AddLast d + SetTextAreaText textarea,d.add,d.pos,d.del.length + SelectTextAreaText(textarea,d.pos0,d.count0) + UpdateCursor + SetCode TextAreaText(textarea),d + End Method + + Method RefreshStyle() + Local rgb:TColor + Local src$ + Local charwidth + charwidth=host.options.editfont.CharWidth(32) + SetTextAreaTabs textarea,host.options.tabsize*charwidth + SetMargins textarea,4 + SetTextAreaFont textarea,host.options.editfont + rgb=host.options.editcolor + SetTextAreaColor textarea,rgb.red,rgb.green,rgb.blue,True + rgb=host.options.styles[0].color + SetTextAreaColor textarea,rgb.red,rgb.green,rgb.blue,False + src=cleansrc + cleansrc="" + cleansrcl="" + cursorpos=0 + SetCode(src) + End Method + + Function IsntAlphaNumeric(c) 'lowercase test only + If c<48 Return True + If c>=58 And c<95 Return True + If c=96 Return True + If c>=123 Return True + End Function + + Function IsntAlphaNumericOrQuote(c) 'lowercase test only + If c=34 Return False + If c<48 Return True + If c>=58 And c<95 Return True + If c=96 Return True + If c>=123 Return True + End Function + + Function IsCode(src$,p) + Local n + Local l = src.FindLast(EOL$,src.length-p) + If l=-1 l=0 + Local q = src.Find("'",l) + If q<>-1 And q

    =0 + p=src.Find("#",pos) + If p=-1 Exit + q=p + While q>0 + q:-1 + c=src[q] + If c=13 Return p + If c=10 Return p + If c=32 Or c=9 Continue + Exit + Wend + If q<0 Return p + pos=p+1 + Wend + Return src.length + End Function + + Function FindToken(token$,src$,pos) 'lowercase src only! + Local p,c + Local n=token.length + While pos>=0 + p=src.Find(token,pos) + If p=-1 Exit + c=10 If p>0 c=src[p-1] + If isntalphanumeric(c) + If p+n"end " Return p + EndIf + EndIf + EndIf + pos=p+1 + Wend + Return src.length + End Function + + Function FindEndToken(token$,src$,pos,returnlast=False) 'if true returns first character after endtoken + Local p,q,e$,n + + p=pos + e$="end"+token + n=e.length + While p32 Return False + Next + Return True + End Function + +' rem and endrem must be first nonwhitespace on line - following funcs are for lowercase src only + + Function FindRem(src$,pos) + While pos0 + If pos>src.length Exit 'fixed endrem on lastline overrun + p=src.FindLast("rem",src.length-pos) + If p=-1 Exit + If isntalphanumeric(src[p+3]) And IsFirstCharOnLine(src,p) Return p + pos=p-1 + Wend + Return -1 + End Function + + Method IsRemmed(pos,src$) + Local p = FindPrevRem(src$,Min(pos+3,src.length)) + If p<0 Return + p=FindEndRem(src$,p) + If p<0 Or pos

    = 0) Or (tidyqueue1 >= 0) Or (tidyqueue2 >= 0)) + EndMethod + + Method ClearTidyQueue(start,endpos) + If start<=deferpos And deferpos < endpos Then deferpos = -1 + If start<=tidyqueue1 And tidyqueue1 < endpos Then tidyqueue1 = -1 + If start<=tidyqueue2 And tidyqueue2 < endpos Then tidyqueue2 = -1 + EndMethod + + Method SetCode(src$,diff:TDiff=Null) + Local same,i,p,startp,p1,q,r,a,t$,h$,lsrc$,r0,r1,cpos,autocap + Local style:TTextStyle[5],s:TTextStyle +' update dirty flag + CheckDirty src + same = Not ((diff) Or (src<>cleansrc)) + If same And Not (diff Or HasTidyQueue()) Then Return + If Not isbmx Or Not host.quickhelp Or Not host.options.syntaxhighlight + If Not same Then + cleansrc=src + cleansrcl=src.ToLower() + EndIf + Return + EndIf +' doit + autocap=host.options.autocapitalize + If same Then lsrc = cleansrcl Else lsrc=src.ToLower() + cpos=TextAreaCursor(textarea,TEXTAREA_CHARS) + LockTextArea textarea + style=host.options.styles +' calculate highlight region + + If diff + p=diff.pos + p1=p+diff.add.length + If Not diff.add.length Then + p:-diff.del.length + EndIf + ElseIf HasTidyQueue() + p=src.length + If (deferpos>=0) Then + p = Min(p,deferpos) + p1 = Max(p1,deferpos+1) + EndIf + If (tidyqueue1>=0) Then + p = Min(p,tidyqueue1) + p1 = Max(p1, tidyqueue1+1) + EndIf + If (tidyqueue2>=0) Then + p = Min(p,tidyqueue2) + p1 = Max(p1, tidyqueue2+1) + EndIf + Else + p=firstdiff(src,cleansrc) + p1=lastdiff(src,cleansrc) + EndIf + q=src.length-cleansrc.length + If p1-p"EndRem" SetTextAreaText textarea,"EndRem",r1-6,6 + If lsrc[r1-7..r1]="end rem" And src[r1-7..r1]<>"End Rem" SetTextAreaText textarea,"End Rem",r1-7,7 + EndIf + ClearTidyQueue(p,r1) + p=r1 + EndIf + EndIf +' if was remmed and now isn't move p1 down to nearest rem or endrem + If WasRemmed(p,lsrc) + r0=FindRem(lsrc,p) + r1=FindEndRem(lsrc,r0,True) + p1=Max(p1,Min(r0,r1)) + EndIf +' highlight code + ClearTidyQueue(p,p1) + + s=style[NORMAL] + If p1>p s.format(textarea,p,p1-p) + startp = p + + While p-1 And r-1 And r-1 And r=65 And a<91) Or (a>=97 And a<123) Or (a=95) + q=p+1 + While q=58 And a<65 Exit + If a>=91 And a<95 Exit + If a=96 Exit + If a>122 Exit + q:+1 + Wend + t$=src[p..q] + h$=host.quickhelp.token(t$) + If h$ + If h$<>t$ And autocap + If cpos

    q + SetTextAreaText textarea,h,p,h.length + Else + deferpos=q + EndIf + EndIf + s=style[KEYWORD] + If h$="Rem" And IsFirstCharOnLine(lsrc,p) ' Not (p>4 And lsrc[p-4..p]="end ") + If q<>cpos + q=FindEndRem(lsrc,p,True) + s=style[COMMENT] + Else + deferpos=q + EndIf + EndIf + s.format(textarea,p,q-p) + EndIf + p=q + Continue + EndIf +' numbers + If (p=0 Or IsntAlphaNumeric(lsrc[p-1])) And ((a>=$30 And a<$3A) Or (a=$24) Or (a=$25) Or (a=$2E)) '0-9, $, %, . + q=p+1 + Local hexed:Int = (a=$24), binaried:Int = (a=$25), dots:Int = (a=$2E) + Local valid:Int = Not(hexed Or binaried Or dots) + + While q<(p1) + a=lsrc[q] + q:+1 + If (a>=$30 And a<$3A) Then + valid = True + Continue '0-9 + EndIf + If hexed + If (a>=$61 And a<$67) Then 'a-f (only test lower as 'a' var is from lsrc) + valid = True + Continue + EndIf + EndIf + If (a=$2E) Then + 'Hex or Binary literals don't support decimal points + If Not (hexed Or binaried) Then + dots:+1 + 'Fix for slicing '..' syntax + If src[q-2] = $2E Then + dots:-2 + q:-2 + Exit + EndIf + 'End Fix + Continue + EndIf + EndIf + If Not IsntAlphaNumeric(a) Then valid = False + q:-1 + Exit + Wend + If valid And dots < 2 Then style[NUMBER].format(textarea,p,(q-p)) + 'Fix for slicing '..' syntax + If q currentbrackets[0] And cln1 <= currentbrackets[0]) Then + If currentbrackets[0]>-1 Then tidyqueue1 = currentbrackets[0] + EndIf + If Not(cln2 > currentbrackets[1] And cln1 <= currentbrackets[1]) Then + If currentbrackets[1]>-1 Then tidyqueue2 = currentbrackets[1] + EndIf + currentbrackets = Null + If Not alwaysfind Then Return + EndIf + + If host.options.bracketmatching And isbmx And Not IsRemmed(currentcharpos,lsrc) Then + + limit = Min(lsrc.length,currentcharpos+2) + + While currentcharpos >= 0 And currentcharpos < limit + If IsCode(lsrc,currentcharpos) Then + Select lsrc[currentcharpos] + Case Asc("(");otherchar = Asc(")");Exit + Case Asc("{");otherchar = Asc("}");Exit + Case Asc("[");otherchar = Asc("]");Exit + ' Negate char code to search backwards + Case Asc(")");otherchar = -Asc("(");Exit + Case Asc("}");otherchar = -Asc("{");Exit + Case Asc("]");otherchar = -Asc("[");Exit + EndSelect + EndIf + currentcharpos:+1 + Wend + + If otherchar Then + + absotherchar = (Abs otherchar) + currentchar = lsrc[currentcharpos] + + LockTextArea textarea + style[MATCHING].format(textarea, currentcharpos, 1) + currentbrackets = [currentcharpos,-1] + + othercharpos = currentcharpos+(otherchar/absotherchar) + + While othercharpos < lsrc.length And othercharpos >= 0 + + If IsCode(lsrc,othercharpos) Then + Select lsrc[othercharpos] + Case Asc(" "), Asc("~t") + 'Do nothing + Case Asc("'") + Exit + Case absotherchar + If check < 0 Then Exit Else check = 0 + If depth Then + depth:-1 + Else + style[MATCHING].format(textarea, othercharpos, 1) + currentbrackets[1] = othercharpos + UnlockTextArea textarea + Return + EndIf + Case Asc("~n") + If (otherchar/absotherchar) > 0 Then + If check = 2 Then check = 0 Else Exit + Else + If check < 0 Then Exit Else check = -2 + EndIf + Case Asc(".") + check:+1 + Default + If check < 0 Then Exit Else check = 0 + If lsrc[othercharpos] = lsrc[currentcharpos] Then depth:+1 + EndSelect + EndIf + + othercharpos:+(otherchar/absotherchar) + + Wend + + UnlockTextArea textarea + + EndIf + + EndIf + + EndMethod + + Method AutoIndent() + Local p,q + Local c = TextAreaCursor(textarea,TEXTAREA_CHARS) + Local n = TextAreaSelLen(textarea,TEXTAREA_CHARS) + If cc q=c + EndIf + SetTextAreaText textarea,EOL$+cleansrc[p..q],c,n + SelectTextAreaText textarea,c+1+q-p,0 + UpdateCursor + UpdateCode + End Method + + Method IndentCode() + Local a$ +' blockindent + Local p0 = TextAreaCursor(textarea,TEXTAREA_LINES) + Local p1 = TextAreaSelLen(textarea,TEXTAREA_LINES) +' v122: make sure the entire block is selected (start cursor pos may in the middle of the line) + SelectTextAreaText textarea , p0 , p1 , TEXTAREA_LINES + UpdateCursor + For Local i:Int = 0 Until p1 + a$="~t"+TextAreaText(textarea,p0+i,1,TEXTAREA_LINES) + SetTextAreaText textarea,a$,p0+i,1,TEXTAREA_LINES + Next + SelectTextAreaText textarea,p0,p1,TEXTAREA_LINES + UpdateCursor + UpdateCode + End Method + + Method OutdentCode() + Local a$,modified +' blockoutdent + Local p0 = TextAreaCursor(textarea,TEXTAREA_LINES) + Local p1 = TextAreaSelLen(textarea,TEXTAREA_LINES) +' v122: make sure the entire block is selected (start cursor pos may in the middle of the line) + SelectTextAreaText textarea , p0 , p1 , TEXTAREA_LINES + UpdateCursor + For Local i:Int = 0 Until p1 + a$=TextAreaText(textarea,p0+i,1,TEXTAREA_LINES) + If a[0]=9 a$=a$[1..];modified=True + SetTextAreaText textarea,a$,p0+i,1,TEXTAREA_LINES + Next + If Not modified + For Local i:Int = 0 Until p1 + a$=TextAreaText(textarea,p0+i,1,TEXTAREA_LINES) + If a[0]=32 a$=a$[1..] + SetTextAreaText textarea,a$,p0+i,1,TEXTAREA_LINES + Next + EndIf + SelectTextAreaText textarea,p0,p1,TEXTAREA_LINES + UpdateCursor + UpdateCode + End Method + + Function FilterKey(event:TEvent,context:Object) +' If event.id<>EVENT_KEYCHAR Return 1 + Local id=event.id + Local key=event.data + Local mods=event.mods + Local this:TOpenCode=TOpenCode(context) +?MacOS + If key=25 And mods=MODIFIER_SHIFT key=KEY_TAB +? + If id=EVENT_KEYCHAR And this And key=KEY_TAB And TextAreaSelLen( this.textarea,TEXTAREA_CHARS ) + Select mods + Case MODIFIER_NONE + this.IndentCode + Case MODIFIER_SHIFT + this.OutdentCode + End Select + Return 0 + EndIf + + If id=EVENT_KEYDOWN And key=KEY_ENTER And this And this.host.options.autoindent + this.AutoIndent() + Return 0 + EndIf + + Return 1 + End Function + + Method OnEvent() + Select EventSource() + Case textarea + Select EventID() + Case EVENT_GADGETMENU + PopupWindowMenu host.window,editmenu + Case EVENT_GADGETACTION + UpdateCode + Case EVENT_GADGETSELECT + UpdateCursor + End Select + End Select + End Method + + Method SetDirty( bool ) + If dirty=bool Return + dirty=bool + name=StripDir(path) + If (dirty) name:+"*" + If (host.lockedpanel=Self) name=LocalizeString("{{tab_locked:%1}}").Replace("%1",name) + host.RefreshPanel Self + PollSystem + End Method + + Method SetLocked( bool ) + Local locked:TOpenCode = TOpenCode(host.lockedpanel) + If locked And locked<>Self locked.SetLocked False + name=StripDir(path) + If (dirty) name:+"*" + If (bool) + name=LocalizeString("{{tab_locked:%1}}").Replace("%1",name) + host.lockedpanel=Self + Else + host.lockedpanel=Null + EndIf + host.RefreshPanel Self + End Method + + Method Help() + If Not host.quickhelp Return + Local p = TextAreaCursor(textarea,TEXTAREA_CHARS) + Local a$ = WordAtPos(cleansrc,p) + If a=helpcmd + Local l$ = host.quickhelp.link(a$) + If l + host.helppanel.go host.bmxpath+l$ + EndIf + Else + helpcmd=a$ + helpstring$=host.quickhelp.help(a$) + UpdateStatus 'host.setstatus helpstring$ + EndIf + End Method + + Method Find() + host.findreq.ShowFind WordAtPos(cleansrc,TextAreaCursor(textarea,TEXTAREA_CHARS)) + End Method + + Method FindNext(s$) + If s seek=s Else s=seek + Local p = TextAreaCursor(textarea,TEXTAREA_CHARS) + p:+TextAreaSelLen(textarea,TEXTAREA_CHARS) +' case insensitive + Local l$ = s.toLower() + p=cleansrcl.Find(l$,p) + If p=-1 p=cleansrcl.Find(l$) +' case sensitive +' p=cleansrc.Find(s$,p+1) +' if p=-1 p=cleansrc.Find(s$) + If p=-1 + Notify LocalizeString("{{find_notification_cannotfind}}").Replace("%1",s) + Return False + Else + SelectTextAreaText textarea,p,Len s,TEXTAREA_CHARS + UpdateCursor + Return True + EndIf + End Method + + Method ReplaceAll(s$,r$) + Local t$ = TextAreaText( textarea ).ToLower() + Local c = TextAreaCursor(textarea,TEXTAREA_CHARS),i,p + s = s.ToLower() + Repeat + Local i2=t.Find( s,i ) + If i2=-1 Exit + p:+i2-i + i=i2+s.length + SelectTextAreaText textarea,p,s.length + UpdateCursor + UpdateCode + SetTextAreaText textarea,r,p,s.length + If p0 + f$=r[..p] + r$=r[p+1..] + ReplaceAll f$,r$ + Else + p=TextAreaCursor(textarea,TEXTAREA_CHARS) + n=TextAreaSelLen(textarea,TEXTAREA_CHARS) + If Not n Return + SetTextAreaText textarea,r$,p,n + SelectTextAreaText textarea,p+r.length,0 + UpdateCursor + UpdateCode + EndIf + Return True + End Method + + Method ReadSource(path$) + Local src$ + src=CacheAndLoadText(path) + src=src.Replace(Chr(13),"") + src=src.Replace(Chr(11),"") + LockTextArea textarea + SetTextAreaText textarea,src + UnlockTextArea textarea + filesrc=TextAreaText(textarea) + cleansrc="" + cleansrcl="" + ActivateGadget textarea + End Method + + Method SaveSource(file$) + If host.options.autobackup + DeleteFile file+".bak" + RenameFile file,file+".bak" + EndIf + Local src$ = TextAreaText(textarea) + filesrc=src + src=src.Replace(Chr(13),Chr(10)) + src=src.Replace(Chr(11),"") + Local txt$ = src.Replace$(Chr(10),Chr(13)+Chr(10)) + + Try + SaveText txt,file + Catch exception:Object + Local err$=String(exception) + Notify "Save Error~n"+err + Return False + EndTry + + path=host.FullPath$(file) + dirty=True + SetDirty False + host.AddRecent(path$) + Return True + End Method + + Method BuildSource(quick,debug,threaded,gui,run) + Local cmd$,out$,arg$ + If isbmx Or isc Or iscpp + cmd$=quote(host.bmkpath) + cmd$:+" makeapp" + If run cmd$:+" -x" + If debug cmd$:+" -d" Else cmd$:+" -r" '-v + If threaded cmd$:+" -h" + If gui cmd$:+" -t gui" + If Not quick cmd$:+" -a" + If debug Or threaded + out=StripExt(host.FullPath(path)) + If debug out:+".debug" + If threaded out:+".mt" + cmd:+" -o "+quote(out$)+" " + EndIf + cmd$:+" "+quote(host.FullPath(path)) + If run + arg$=host.GetCommandLine() + If arg cmd$:+" "+arg + EndIf + host.execute cmd,"Building "+StripExt(StripDir(path)) ',exe$ + Else + If ishtml + host.helppanel.Go "file://"+path + Else +'see what the system shell thinks of the file + Local cd$=CurrentDir() + ChangeDir ExtractDir(path) + cmd=StripDir(path) + host.execute cmd,"Building "+cmd + ChangeDir cd + EndIf + EndIf +' print cmd + End Method + + Method Save() + Local file$ = path + If host.IsTempPath(path) + file=RequestFile(LocalizeString("{{request_saveas_title}}"),FileTypeFilters,True,"") + If file="" Return False + If ExtractExt(file)="" file=file+".bmx" + dirty=True + EndIf + If dirty SaveSource(file) + Return True + End Method +' common command interface + + Method Invoke(command,argument:Object=Null) + Local file$,ex$ + Local p,res + Select command + Case TOOLSHOW + host.SetCodeNode GetNode() + host.SetTitle path +' simon was here If textarea Edit + If textarea ActivateGadget textarea + + Case TOOLCLOSE + If dirty 'Or host.IsTempPath(path) + Invoke(TOOLSHOW) + p=Proceed(LocalizeString("{{request_savechanges}}").Replace("%1",name)) 'the current file? + If p=-1 Return True + If p=1 + If Not Save() Return True + EndIf + EndIf + If codenode Then + codenode.Free() + codenode=Null + EndIf + 'Added just in case MaxGUI driver doesn't handle properly. + SetGadgetFilter textarea,Null,Null + 'Seb gone. + host.RemovePanel Self + FreeGadget(editmenu) + Case TOOLSAVE + Save + Case TOOLQUICKSAVE + file=path + If dirty SaveSource(file) + Case TOOLSAVEAS + file=path + If host.IsTempPath(path) file$="" + file=RequestFile(LocalizeString("{{request_saveas_title}}"),FileTypeFilters,True,file) + If file="" Return + ex$=ExtractExt(file) + If ex$="" + file=file+".bmx" + isbmx=True + Else + isbmx=(ex.ToLower()="bmx") + ishtml=(ex.ToLower()="html") + isc=(ex.ToLower()="c") + iscpp=(ex.ToLower()="cpp" Or ex.ToLower()="cxx") + EndIf + SaveSource(file$) + RefreshStyle() + GetNode().Refresh + SetDirty False + host.SetTitle path + Case TOOLGOTO + Local line=Int(String(argument)) + SelectTextAreaText textarea,line-1,0,TEXTAREA_LINES + UpdateCursor + ActivateGadget textarea + Case TOOLFIND + Find + Case TOOLFINDNEXT + Return FindNext(String(argument)) + Case TOOLREPLACE + Return FindReplace(String(argument)) + Case TOOLBUILD + BuildSource host.quickenabled,host.debugenabled,host.threadedenabled,host.guienabled,False + Case TOOLRUN + BuildSource host.quickenabled,host.debugenabled,host.threadedenabled,host.guienabled,True + Case TOOLLOCK + SetLocked True + Case TOOLUNLOCK + SetLocked False + Case TOOLHELP + Help() + Case TOOLUNDO + Undo() + Case TOOLREDO + Redo() + Case TOOLREFRESH + RefreshStyle() + Case TOOLCUT + GadgetCut textarea + UpdateCursor() + UpdateCode() + Case TOOLCOPY + GadgetCopy textarea + Case TOOLPASTE + GadgetPaste textarea + UpdateCursor() + UpdateCode() + Case TOOLSELECTALL + SelectTextAreaText textarea + UpdateCursor() + Case TOOLINDENT + IndentCode() + Case TOOLOUTDENT + OutdentCode() + Case TOOLPRINT + GadgetPrint textarea + End Select + End Method + + Function CreateEditMenu:TGadget() + Local edit:TGadget = CreateMenu("{{popup_edit}}",0,Null) + CreateMenu "{{popup_edit_quickhelp}}",MENUQUICKHELP,edit + CreateMenu "",0,edit + CreateMenu "{{popup_edit_cut}}",MENUCUT,edit + CreateMenu "{{popup_edit_copy}}",MENUCOPY,edit + CreateMenu "{{popup_edit_paste}}",MENUPASTE,edit + CreateMenu "",0,edit + CreateMenu "{{popup_edit_selectall}}",MENUSELECTALL,edit + CreateMenu "",0,edit + CreateMenu "{{popup_edit_blockindent}}",MENUINDENT,edit + CreateMenu "{{popup_edit_blockoutdent}}",MENUOUTDENT,edit + CreateMenu "",0,edit + CreateMenu "{{popup_edit_find}}",MENUFIND,edit + CreateMenu "{{popup_edit_findnext}}",MENUFINDNEXT,edit + CreateMenu "{{popup_edit_replace}}",MENUREPLACE,edit + CreateMenu "{{popup_edit_goto}}",MENUGOTO,edit + Return edit + End Function + + Method MakePathTemp() +' prepends "." to file name with code borrowed from SaveAs + Local file$=ExtractDir(path)+"/."+StripDir(path) + SaveSource(file$) +' Refresh + GetNode().Refresh +' setdirty False + host.SetTitle path + End Method + + Function Create:TOpenCode(path$,host:TCodePlay) + Local code:TOpenCode + Local stream:TStream + Local isnew + If path + If FileType(path)<>FILETYPE_FILE + Return Null + EndIf + stream=ReadFile(path) + If Not stream +' Notify "Open could not read from "+path + Return Null + EndIf + CloseFile stream + Else + TEMPCOUNT:+1 + path=host.bmxpath+"/tmp/untitled"+TEMPCOUNT+".bmx" + isnew=True + EndIf + code=New TOpenCode + code.host=host + code.active=True + code.path=host.FullPath(path) + code.editmenu=CreateEditMenu() + codeplay.addpanel(code) + code.textarea=CreateTextArea(0,0,ClientWidth(code.panel),ClientHeight(code.panel),code.panel,0) + DelocalizeGadget code.textarea + SetGadgetFilter code.textarea,code.FilterKey,code + SetTextAreaText code.textarea,"~n" + SetGadgetLayout code.textarea,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED + code.RefreshStyle() + + If isnew + code.SaveSource path + code.filesrc="~n" + ActivateGadget code.textarea + Else + host.UpdateProgress "Reading Stream" + code.ReadSource(path) + EndIf + + If ExtractExt(path).toLower()="bmx" code.isbmx=True + If ExtractExt(path).toLower()="c" code.isc=True + If ExtractExt(path).toLower()="cpp" code.iscpp=True + If ExtractExt(path).toLower()="cxx" code.iscpp=True + If ExtractExt(path).toLower()="html" code.ishtml=True + If ExtractExt(path).toLower()="htm" code.ishtml=True + code.UpdateCode False + code.filesrc=TextAreaText(code.textarea) + Return code + End Function + +End Type + +Type TRect + Field x,y,w,h + + Method Set(xpos,ypos,width,height) + x=xpos;y=ypos;w=width;h=height + End Method + + Method ToString$() + Return ""+x+","+y+","+w+","+h + End Method + + Method FromString(s$) + Local p,q,r + p=s.Find(",")+1;If Not p Return + q=s.Find(",",p)+1;If Not q Return + r=s.Find(",",q)+1;If Not r Return + x=Int(s[..p-1]) + y=Int(s[p..q-1]) + w=Int(s[q..r-1]) + h=Int(s[r..]) + End Method + + Method IsOutside(tx,ty,tw,th) + If x+w<=tx Or y+h<=ty Return True + If x>=tx+tw Or y>=ty+th Return True + End Method + +End Type + +Type TCodePlay + + Const EDITMODE=1 + Const DEBUGMODE=2 + + Field bmxpath$,bmkpath$ + Field panels:TToolPanel[] + Field helppanel:THelpPanel + Field currentpanel:TToolPanel + Field output:TOutputPanel + Field lockedpanel:TToolPanel + Field activepanel:TToolPanel + + Field cmdlinereq:TCmdLineRequester + Field cmdline$ + 'Field syncmodsreq:TSyncModsRequester + Field gotoreq:TGotoRequester + Field findreq:TFindRequester + Field replacereq:TReplaceRequester + Field options:TOptionsRequester +' Field progress:TProgressRequester + Field activerequesters:TList = New TList + Field projectreq:TProjectRequester + Field projectprops:TProjectProperties + Field searchreq:TSearchRequester + Field aboutreq:TAboutRequester + + + Field eventhandlers:TList=New TList + Field window:TGadget,menubar:TGadget,toolbar:TGadget,client:TGadget,tabbar:TGadget + Field split:TSplitter + Field debugtree:TDebugTree + + Field root:TNode + Field helproot:TNode + Field projects:TProjects + Field coderoot:TNode + Field navbar:TNavBar + + Field mode + Field debugcode:TOpenCode + + Field quickenable:TGadget,quickenabled 'menu,state + Field debugenable:TGadget,debugenabled 'menu,state + Field threadedenable:TGadget,threadedenabled + Field guienable:TGadget,guienabled 'menu,state + Field quickhelp:TQuickHelp + Field running + Field recentmenu:TGadget + Field recentfiles:TList=New TList + Field recentmenus:TGadget[] + Field openlist:TList=New TList + Field openlock$ + Field projlist:TList=New TList + Field winsize:TRect=New TRect + Field winmax,tooly,splitpos,debugview,navtab + Field progress,splitorientation + +?MacOS + Method RanlibMods() + + Local cmd$=Quote( bmxpath+"/bin/bmk" )+" ranlibdir "+Quote( bmxpath+"/mod" ) + system_ cmd + + End Method +? + + Method CheckVersion$() + Local process:TProcess + Local bytes:Byte[] + Local cmd$,version$ + + cmd$=bmxpath+"/bin/bcc" + +?win32 + cmd:+".exe" +? + + cmd=Quote(cmd) + process=CreateProcess(cmd$,HIDECONSOLE) + If process + Repeat + Delay 10 + bytes=process.pipe.ReadPipe() + If bytes + version:+String.FromBytes(bytes,bytes.length) + EndIf + Until Not process.Status() + EndIf + + If version="" + Notify "Unable to determine BlitzMax version.~n~nPlease reinstall BlitzMax to repair this problem." + End + EndIf + + BCC_VERSION=version.Trim() + +' print "bcc version="+version + + If version.find("(expired)")>-1 'Demo timed out + Notify "This demo version of BlitzMax has expired.~n~nPlease visit www.blitzbasic.com to buy the full version." + End + EndIf + + If version.find("Demo Version")>-1 'Valid demo version + is_demo=True + Notify version+"~nTo purchase the full version please visit www.blitzbasic.com." + Notify ABOUTDEMO + EndIf + + End Method + + Method OpenProgress(message$) +' progress.Open message + DisableGadget window + SetStatus message + progress=-1 + End Method + + Method CloseProgress() +' progress.Hide + SetStatus "" + EnableGadget window + progress=0 + End Method + + Method UpdateProgress(message$,value=0) 'returns false if cancelled +' Return progress.Update(message,value) + If progress + If progress/5<>value/5 + SetStatus message+" "+value+"%" + progress=value +' Pollsystem + EndIf + EndIf + End Method + + Method FullPath$(path$) + If path[..8]="$BMXPATH" path=bmxpath+path[8..] + If Not path.Contains("::") Then path = RealPath(path) +?win32 + path=path.Replace("\","/") +? + Return path + End Method + + Method IsTempPath(path$) + If path[..bmxpath.length+5]=bmxpath+"/tmp/" Return True + End Method + + Method AddDefaultProj(p$) + Local projdata:TList = New TList + projdata.AddLast p + projlist.AddLast projdata + End Method + + Method ReadConfig() + Local stream:TStream + Local f$,p,a$,b$ +' defaults + Local wh=GadgetHeight(Desktop())-80'32 + Local ww=wh + Local wx=(GadgetWidth(Desktop())-ww)/2 + Local wy=(GadgetHeight(Desktop())-wh)/2 + winsize.set( wx,wy,ww,wh ) + quickenabled=False + debugenabled=True + threadedenabled=False + guienabled=True + splitpos=200;splitorientation = SPLIT_VERTICAL +' read ini + stream=ReadFile(bmxpath+"/cfg/ide.ini") + If Not stream + AddDefaultProj "Samples|samples" + If Not is_demo + AddDefaultProj "Modules Source|mod" + AddDefaultProj "BlitzMax Source|src" + EndIf + Return + EndIf + options.read(stream) + options.Snapshot + + Local projdata:TList + + While Not stream.Eof() + f$=stream.ReadLine() + p=f.find("=") + If p=-1 Continue + a$=f[..p] + b$=f[p+1..] + Select a$ + Case "ide_version" + + Case "file_recent" + recentfiles.addlast b$ + Case "file_open" + openlist.addlast b$ + Case "prg_quick" + quickenabled=Int(b$) + Case "prg_debug" + debugenabled=Int(b$) + Case "prg_threaded" + threadedenabled=Int(b$) + Case "prg_gui" + guienabled=Int(b$) + Case "cmd_line" + cmdline=b$ + Case "prg_locked" + openlock=b$ + Case "win_size" + winsize.FromString(b$) + Case "win_max" + winmax=Int(b$) + Case "split_position" + splitpos=Int(b$) + Case "split_orientation" + splitorientation=Int(b$) + Case "proj_node" + projdata=New TList + projdata.AddLast b + projlist.AddLast projdata + Case "proj_data" + If projdata projdata.AddLast b + 'Case "sync_state" + 'syncmodsreq.FromString b$ + End Select + Wend + stream.close() + End Method + + Method WriteConfig() + Local panel:TToolPanel + Local node:TNode + Local f$ + + Local stream:TStream = WriteFile(bmxpath+"/cfg/ide.ini") + If Not stream Return +' options + options.write(stream) +' defaults + stream.WriteLine "[Defaults]" + stream.WriteLine "ide_version="+IDE_VERSION$ + stream.WriteLine "prg_quick="+quickenabled + stream.WriteLine "prg_debug="+debugenabled + stream.WriteLine "prg_threaded="+threadedenabled + stream.WriteLine "prg_gui="+guienabled + stream.WriteLine "win_size="+winsize.ToString() + stream.WriteLine "win_max="+winmax + stream.WriteLine "split_position="+SplitterPosition(split) + stream.WriteLine "split_orientation="+SplitterOrientation(split) + stream.WriteLine "cmd_line="+cmdline + 'stream.WriteLine "sync_state="+syncmodsreq.ToString() + If lockedpanel stream.WriteLine "prg_locked="+lockedpanel.path + For f$=EachIn recentfiles + stream.WriteLine "file_recent="+f$ + Next + For Local panel:TToolPanel = EachIn panels + f$=panel.path + If f$ And Not IsTempPath(f$) stream.WriteLine "file_open="+f$ + Next + projects.write(stream) + stream.close + End Method + + Method CloseAll(dontask,inccurrent=True) 'returns true if successful + Local count, cancel + For Local panel:TToolPanel = EachIn panels + If TOpenCode(panel) And (inccurrent Or currentpanel <> panel) count:+1 + Next + If (Not count) Or dontask Or Confirm(LocalizeString("{{request_closeall}}")) + For Local panel:TToolPanel = EachIn panels[..] 'Use a copy of the original array for iterating. + If (inccurrent Or currentpanel <> panel) And panel.invoke(TOOLCLOSE) Then + cancel=True + Exit + EndIf + Next + Return Not cancel + EndIf + End Method + + Method Quit() + WriteConfig() + If CloseAll(True) running=False + End Method + + Method DebugExit() + If debugcode + debugtree.cancontinue = False + debugcode.Edit 'restore cursor etc. + debugcode=Null + EndIf + SetMode EDITMODE + RefreshToolbar() + End Method + + Method DebugSource(path$,line,column) + Local code:TOpenCode + path=FullPath(path) + code=OpenSource(path) + If Not code Then + Notify(LocalizeString("{{loaderror_failed}}").Replace("%1",path), True) + Return + EndIf + If debugcode And debugcode<>code Then debugcode.Edit() 'restore cursor etc. + debugcode=code + debugcode.debug(line,column) + ActivateWindow window + PollSystem + End Method + + Method SetMode(m) + If mode=m Return + ActivateWindow window + Select m + Case DEBUGMODE + navtab=navbar.SelectedView() + navbar.SelectView debugview + Case EDITMODE + navbar.SelectView navtab + End Select + mode=m + RefreshToolbar + End Method + + Method RefreshMenu() + TOpenCode.RefreshHighlightingMsg() + UpdateWindowMenu window + EndMethod + + Method RefreshToolbar() + Local i +' sourceedit buttons + If THelpPanel(CurrentPanel) + DisableGadgetItem toolbar,TB_CLOSE + Else + EnableGadgetItem toolbar,TB_CLOSE + EndIf + If TOpenCode(CurrentPanel) + EnableGadgetItem toolbar,TB_SAVE + For i=TB_CUT To TB_FIND + EnableGadgetItem toolbar,i + Next + Else + DisableGadgetItem toolbar,TB_SAVE + For i=TB_CUT To TB_FIND + DisableGadgetItem toolbar,i + Next + EndIf +' debug buttons + If mode = DEBUGMODE And debugtree.cancontinue Then + If GadgetItemIcon( toolbar, TB_BUILDRUN ) = TB_BUILDRUN Then + ModifyGadgetItem( toolbar, TB_BUILDRUN, "", GADGETITEM_LOCALIZED, TB_CONTINUE, "{{tb_continue}}" ) + EndIf + Else + If GadgetItemIcon( toolbar, TB_BUILDRUN ) <> TB_BUILDRUN Then + ModifyGadgetItem( toolbar, TB_BUILDRUN, "", GADGETITEM_LOCALIZED, TB_BUILDRUN, "{{tb_buildrun}}" ) + EndIf + EndIf + For i=TB_STEP To TB_STEPOUT + If mode=DEBUGMODE And debugtree.cancontinue Then + EnableGadgetItem toolbar,i + Else + DisableGadgetItem toolbar,i + EndIf + Next +' stop button + If output And output.process + EnableGadgetItem toolbar,TB_STOP + Else + DisableGadgetItem toolbar,TB_STOP + EndIf + End Method + + Method IsSourceOpen(path$) + Local p$ = FullPath(path) + For Local panel:TToolPanel = EachIn panels + If panel.path=p Return True + Next + End Method + + Method OpenSource:TOpenCode(path$) + Local code:TOpenCode + Local ext$,p$ + If path$="." + path$=RequestFile(LocalizeString("{{request_openfile}}"),FileTypeFilters ) + If path$="" Return + EndIf +' check if already open + p$=FullPath(path).ToLower() + For Local panel:TToolPanel = EachIn panels + If panel.path.ToLower()=p + SelectPanel panel + Return TOpenCode(panel) + EndIf + Next +' open based on extension +' Select ExtractExt(Upper(path$)) +' Case "BMX","TXT","BB","CPP","C","S","I","H","HTML","CSS","BAT","FS","VS","README","" + OpenProgress LocalizeString("{{msg_loading}}").Replace("%1",StripDir(path)) + code=TOpenCode.Create(path,Self) + If code + AddRecent code.path + EndIf + CloseProgress + If code + ActivateGadget code.textarea + code.GetNode().Refresh + EndIf + Return code +' end select + End Method + + Method AddRecent(path$) + For Local f$ = EachIn recentfiles + If f$=path$ recentfiles.Remove(f$);Exit + Next + recentfiles.AddFirst(path$) + RefreshRecentFiles + UpdateWindowMenu window + End Method + + Method RefreshRecentFiles() + Local n + For Local m:TGadget = EachIn recentmenus + FreeMenu m + Next + n=Min(recentfiles.count(),16) + recentmenus=New TGadget[n] + n=0 + For Local f$ = EachIn recentfiles + recentmenus[n]=CreateMenu(f$,MENURECENT+n,recentmenu) + n:+1 + If n=16 Exit + Next + End Method + + Method BuildModules(buildall) + Local cmd$,out$,exe$ + output.Stop + SaveAll + cmd$=quote(bmkpath) + cmd$:+" makemods " + + If buildall cmd$:+"-a " + If threadedenabled cmd:+"-h " + + Execute cmd,LocalizeString("{{output_msg_buildingmods}}") + End Method + + Method ImportBB() + Local f$ = RequestFile(LocalizeString("{{request_importbb_title}}"),"bb" ) + If Not f$ Return + Local cmd$ = Quote(bmkpath$) + cmd$:+" convertbb " + cmd$:+quote(FullPath(f$)) + Execute cmd,LocalizeString("{{output_msg_converting}}").Replace("%1",StripExt(StripDir(f$))) + output.wait + OpenSource(StripExt(f$)+".bmx") + End Method + + Method GetCommandLine$() + Return cmdline + End Method + + Method SetCommandLine(text$) + cmdline=text + End Method + + Method SetStatus(text$) + SetStatusText window,text + End Method + + Method Execute(cmd$,mess$="",post$="",home=True,tool:TTool=Null) + If Not output output=TOutputPanel.Create(Self) + output.execute cmd$,mess$,post$,home,tool + End Method + + Method SelectError(path$,column,line) + Local panel:TOpenCode,found + For panel=EachIn panels + If panel.path=path found=True;Exit + Next + If Not found panel=OpenSource(path) + If panel + SelectPanel panel + panel.Debug line,column + EndIf + End Method + + Method ParseError(err$) + Local mess$,file$,p,q + Local line,column +' bcc error + If err$[..13]="Compile Error" + err=err[14..] + p=err.find(EOL$) + If p=-1 p=err.length + mess=err[..p] + err=err[p+1..] + If err[..1]="[" + p=err.find("]") + If p=-1 p=err.length + file$=err[1..p] + p=file.find(";")+1 + If p=0 p=err.length + q=file.find(";",p)+1 + If q=0 q=err.length + line=Int(file[p..q-1]) + column=Int(file[q..]) + file=FullPath(file[..p-1]) + SelectError file,column,line + EndIf + Notify LocalizeString("{{output_error_compileerror}}").Replace("%1",mess) + SetStatus mess + Return + EndIf +' gcc error + err=err.Replace(EOL+" "," ") + While err + p=err.find(EOL) + If p=-1 p:+err.length 'equiv. to p=err.length-1 ;-) + mess=err[..p] + err=err[p+1..] + p=0 + Repeat + p=mess.Find(":",p)+1 + If p=0 Exit + q=mess.Find(":",p) + If q<>-1 + file=mess[..p-1] + line=Int(mess[p..q]) + If line + mess=mess[q+1..] + SelectError file,column,line + Notify LocalizeString("{{output_error_compileerror}}").Replace("%1",mess) + Return + EndIf + p=q+1 + EndIf + Forever + Wend + End Method + + Method AddPanel(tabpanel:TToolPanel) + Local panel:TGadget,index + index=CountGadgetItems(tabbar) + If panels.length<=index panels=panels[..index+1] + AddGadgetItem(tabbar,tabpanel.name$,GADGETITEM_DEFAULT|GADGETITEM_LOCALIZED) + + panel=CreatePanel(0,0,ClientWidth(tabbar),ClientHeight(tabbar),tabbar,0) 'name + SetGadgetLayout panel,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED + tabpanel.panel=panel + + tabpanel.index=index + panels[index]=tabpanel + SelectPanel tabpanel + AddHandler tabpanel + End Method + + Method AddHandler(handler:TEventHandler) + eventhandlers.addlast handler + End Method + + Method RemovePanel(tabpanel:TToolPanel) + Local p:TToolPanel[] + Local index + eventhandlers.remove tabpanel +' unset debugcode + If debugcode=tabpanel debugcode=Null +' activate next panel + If tabpanel=activepanel activepanel=helppanel + If tabpanel=lockedpanel lockedpanel=Null + If tabpanel=currentpanel + index=tabpanel.index+1 + If index>=panels.length index=panels.length-2 + SelectPanel panels[index] + EndIf +' remove from array + p=panels + panels=panels[..panels.length-1] + For index=tabpanel.index To panels.length-1 + panels[index]=p[index+1] + panels[index].index=index + Next +' remove gadget - simon come here, placing before remove needs fix in fltk + FreeGadget tabpanel.panel + RemoveGadgetItem tabbar,tabpanel.index + tabpanel.panel=Null + End Method + + Method HookRequester(req:TRequester) + If Not activerequesters.Contains(req) Then + If req.IsModal() Then + For Local tmpRequester:TRequester = EachIn activerequesters + DisableGadget tmpRequester.window + Next + DisableGadget window + EndIf + activerequesters.AddFirst(req) + EndIf + End Method + + Method UnhookRequester(req:TRequester) + If activerequesters.Contains(req) Then + activerequesters.Remove(req) + If req.IsModal() Then + For Local tmpRequester:TRequester = EachIn activerequesters + EnableGadget tmpRequester.window + Next + EnableGadget window + EndIf + EndIf + EndMethod + + Method SetTitle(title$="") + If title title=" - "+title + SetGadgetText window,"MaxIDE"+title + End Method + + Method SelectPanel(panel:TToolPanel) + Local curr:TToolPanel = currentpanel + currentpanel=panel + If curr And curr<>currentpanel + SelectGadgetItem tabbar,panel.index + ShowGadget panel.panel + If panel.active activepanel=panel + HideGadget curr.panel + RefreshToolbar + EndIf + currentpanel.Invoke TOOLSHOW + End Method + + Method RefreshPanel(panel:TToolPanel) 'call after a name change + ModifyGadgetItem( tabbar,panel.index,panel.name,GADGETITEM_LOCALIZED ) + End Method + + Function OutsideDesktop(winrect:TRect) + Local x,y,w,h + Local desk:TGadget = Desktop() + x=GadgetX(desk) + y=GadgetY(desk) + w=GadgetWidth(desk) + h=GadgetHeight(desk) + Return winrect.IsOutside(x,y,w,h) + End Function + + Method SetCodeNode(code:TNode) + Local node:TNode + If coderoot.kids.count() node=TNode(coderoot.kids.First()) + If node=code Return + If node node.Detach + If code + coderoot.Append code + coderoot.Refresh + coderoot.Open + code.Open + EndIf + End Method + + Method Initialize() + Local open:TOpenCode, splash:TGadget + Local dir$,nomods,pname$,p + Local stream:TStream + + Try + bmxpath=BlitzMaxPath() + Catch err$ + Notify "Unable to determine BlitzMax installation directory." + End + EndTry + + CreateDir bmxpath+"/tmp" + If FileType( bmxpath+"/tmp" )<>FILETYPE_DIR + Notify "Unable to create BlitzMax 'tmp' directory." + End + EndIf +?Win32 + CreateFile bmxpath+"/tmp/t.exe" + If FileType( bmxpath+"/tmp/t.exe" ) <> FILETYPE_FILE + Notify "Unable to write to BlitzMax installation directory.~n"+.. + "Please run MaxIDE as administrator, or reinstall BlitzMax to a different directory." + End + EndIf + DeleteFile bmxpath+"/tmp/t.exe" +? + bmkpath=bmxpath+"/bin/bmk" +?Win32 + bmkpath:+".exe" +? + dir$=bmxpath+"/mod" + If FileType(dir)=FILETYPE_NONE + If Not CreateDir(dir) + Notify "Failed to create %1 directory:~n%2".Replace("%1","Module").Replace("%2",dir) + End + EndIf + nomods=True + EndIf + dir$=bmxpath+"/tmp" + If FileType(dir)=FILETYPE_NONE + If Not CreateDir(dir) + Notify "Failed to create %1 directory:~n%2".Replace("%1","Temp").Replace("%2",dir) + End + EndIf + EndIf + dir$=bmxpath+"/cfg" + If FileType(dir)=FILETYPE_NONE + If Not CreateDir(dir) + Notify "Failed to create %1 directory:~n%2".Replace("%1","Config").Replace("%2",dir) + End + EndIf + EndIf + + CheckVersion() + + splash=CreateWindow("MaxIDE",200,200,400,140,Null,WINDOW_CLIENTCOORDS|WINDOW_HIDDEN|WINDOW_CENTER) + Local panel:TGadget = CreatePanel(0,0,ClientWidth(splash),ClientHeight(splash),splash,0) + SetPanelColor panel,255,255,255;SetPanelPixmap panel, LoadPixmapPNG("incbin::splash.png"), PANELPIXMAP_FIT2 + Local progress:TGadget = CreateProgBar(2,ClientHeight(panel)-22,ClientWidth(panel)-4,20,panel) + ShowGadget splash;PollSystem + + window=CreateWindow("MaxIDE",20,20,760,540,Null,WINDOW_TITLEBAR|WINDOW_RESIZABLE|WINDOW_STATUS|WINDOW_HIDDEN|WINDOW_ACCEPTFILES|WINDOW_MENU) + + ?Linux + SetGadgetPixmap(window, LoadPixmapPNG("incbin::window_icon.png"), GADGETPIXMAP_ICON ) + ? + + cmdlinereq=TCmdLineRequester.Create(Self) + 'syncmodsreq=TSyncModsRequester.Create(Self) + gotoreq=TGotoRequester.Create(Self) + findreq=TFindRequester.Create(Self) + replacereq=TReplaceRequester.Create(Self) + options=TOptionsRequester.Create(Self) +' progress=TProgressRequester.Create(Self) + projectreq=TProjectRequester.Create(Self) + projectprops=TProjectProperties.Create(Self) + searchreq=TSearchRequester.Create(Self) + aboutreq=TAboutRequester.Create(Self) + + UpdateProgBar progress, 0.1;PollSystem + + ReadConfig() + + toolbar=CreateToolbar("incbin::toolbar.png",0,0,0,0,window ) + + RemoveGadgetItem toolbar, TB_CONTINUE + + Rem + SetToolbarTips toolbar, ["{{tb_new}}","{{tb_open}}","{{tb_close}}","{{tb_save}}","","{{tb_cut}}","{{tb_copy}}","{{tb_paste}}","{{tb_find}}","",.. + "{{tb_build}}","{{tb_buildrun}}","{{tb_step}}","{{tb_stepin}}","{{tb_stepout}}","{{tb_stop}}","","{{tb_home}}","{{tb_back}}","{{tb_forward}}"] + End Rem + + If Not options.showtoolbar Then HideGadget toolbar + + If OutsideDesktop(winsize) + winsize.set(20,20,760,540) + EndIf + + UpdateProgBar progress, 0.2;PollSystem + + SetGadgetShape(window, winsize.x, winsize.y, winsize.w, winsize.h) + + client=window + + split=CreateSplitter(0,0,ClientWidth(client),ClientHeight(client),client,SPLIT_VERTICAL) + SetGadgetLayout(split,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED) + + tabbar=CreateTabber(0,0,ClientWidth(SplitterPanel(split,SPLITPANEL_MAIN)),ClientHeight(SplitterPanel(split,SPLITPANEL_MAIN)),SplitterPanel(split,SPLITPANEL_MAIN)) + SetGadgetLayout(tabbar,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED) + + debugtree=TDebugTree.CreateDebugTree(Self) + + root=TNode.CreateNode("{{navtab_home}}") + + helproot=root.AddNode("{{navnode_help}}") + + projects=TProjects.CreateProjects(Self) + root.Append projects + +' opencoderoot=root.AddNode("Open") + coderoot=TNode.CreateNode("{{navtab_code}}") + coderoot.Open() + + navbar=TNavBar.Create(Self,SplitterPanel(split,SPLITPANEL_SIDEPANE)) + + navbar.AddView root + navbar.AddView coderoot + debugview=navbar.AddView(debugtree) + navbar.SelectView 0 + + helproot.Open + projects.Open + + AddHandler navbar + + SetMode EDITMODE + + UpdateProgBar progress, 0.3;PollSystem + + quickhelp=TQuickHelp.LoadCommandsTxt(bmxpath) + + helppanel=THelpPanel.Create(Self) + + output=TOutputPanel.Create(Self) + + activepanel=helppanel + InitMenu + InitHotkeys + + RefreshAll + + UpdateProgBar progress, 0.4;PollSystem 'allow repaint + + Local mkdocs + If FileType( bmxpath+"/docs/html/User Guide/index.html" )<>FILETYPE_FILE + CreateDir bmxpath+"/docs/html" + CreateFile bmxpath+"/docs/html/index.html" + mkdocs=True + EndIf + + helppanel.Home() + + UpdateProgBar progress, 0.5;PollSystem + +' scan projects in projlist + For Local pdata:TList = EachIn projlist + projects.AddProject pdata + Next + + UpdateProgBar progress, 0.6;PollSystem + + Local tmpProgValue# = 0.6 + Local tmpProgStep# + +'open files from .ini restorelist + If options.restoreopenfiles + If Not openlist.IsEmpty() Then tmpProgStep = (0.3/openlist.Count()) + For Local f$=EachIn openlist + open=OpenSource(f$) + If open And f$=openlock open.SetLocked(True) + tmpProgValue:+tmpProgStep;UpdateProgBar progress,tmpProgValue + Next + EndIf + + tmpProgValue = 0.9 + If AppArgs.length > 1 Then tmpProgStep = (0.1/(AppArgs.length-1)) Else tmpProgValue = 1.0 + UpdateProgBar progress,tmpProgValue;PollSystem + +' open files specified in command line + For Local i:Int = 1 Until AppArgs.length + open=OpenSource(AppArgs[i]) + tmpProgValue:+tmpProgStep;UpdateProgBar progress,tmpProgValue;PollSystem + Next + + HideGadget splash;FreeGadget splash + PollSystem + + SetSplitterPosition(split,splitpos);SetSplitterOrientation(split,splitorientation) + + If winmax MaximizeWindow(window) + ShowGadget window + + PollSystem + running=True + + CreateTimer(TIMER_FREQUENCY) + + 'If nomods syncmodsreq.Show + +'build docs if not there + If mkdocs + If Confirm( LocalizeString("{{loaderror_docsnotfound}}") ) And CloseAll( False ) DocMods + EndIf + + End Method + + Method DocMods() + Local cmd$=quote(bmxpath+"/bin/makedocs") + execute cmd,LocalizeString("{{output_msg_rebuildingdocs}}"),MENUTRIGGERSYNCDOCS + ?MacOS + RanLibMods() + ? + End Method + + Method SyncDocs() + helppanel.SyncDocs() + quickhelp=TQuickHelp.LoadCommandsTxt(bmxpath) + helppanel.Home + End Method + + Method InitMenu() + Local menu:TGadget,file:TGadget,edit:TGadget,program:TGadget,tools:TGadget + Local help:TGadget,buildoptions:TGadget + Local buildmods:TGadget,buildallmods:TGadget,syncmods:TGadget,docmods:TGadget + + Local MENUMOD=MODIFIER_COMMAND + + If options.systemkeys + MENUMOD=MODIFIER_CONTROL + EndIf + + menu=WindowMenu(window) + + file=CreateMenu("{{menu_file}}",0,menu) + CreateMenu "{{menu_file_new}}",MENUNEW,file,KEY_N,MENUMOD + CreateMenu "{{menu_file_open}}",MENUOPEN,file,KEY_O,MENUMOD + recentmenu=CreateMenu("{{menu_file_open_recent}}",0,file) + CreateMenu "",0,file + CreateMenu "{{menu_file_closetab}}",MENUCLOSE,file,KEY_W,MENUMOD + CreateMenu "{{menu_file_closealltabs}}",MENUCLOSEALL,file,KEY_W,MENUMOD|MODIFIER_SHIFT + CreateMenu "{{menu_file_closeothertabs}}",MENUCLOSEOTHERS,file,KEY_W,MENUMOD|MODIFIER_ALT + CreateMenu "",0,file + CreateMenu "{{menu_file_save}}",MENUSAVE,file,KEY_S,MENUMOD + CreateMenu "{{menu_file_saveas}}",MENUSAVEAS,file,KEY_S,MENUMOD|MODIFIER_SHIFT + CreateMenu "{{menu_file_saveall}}",MENUSAVEALL,file + CreateMenu "",0,file + + If options.systemkeys +?MacOS + CreateMenu "{{menu_file_nexttab}}",MENUNEXT,file,KEY_RIGHT,MENUMOD + CreateMenu "{{menu_file_prevtab}}",MENUPREV,file,KEY_LEFT,MENUMOD +?Not MacOS + CreateMenu "{{menu_file_nexttab}}",MENUNEXT,file,KEY_RIGHT,MODIFIER_ALT + CreateMenu "{{menu_file_prevtab}}",MENUPREV,file,KEY_LEFT,MODIFIER_ALT +? + Else + CreateMenu "{{menu_file_nexttab}}",MENUNEXT,file,KEY_RIGHT,MENUMOD + CreateMenu "{{menu_file_prevtab}}",MENUPREV,file,KEY_LEFT,MENUMOD + EndIf + CreateMenu "",0,file + CreateMenu "{{menu_file_importbb}}",MENUIMPORTBB,file + CreateMenu "",0,file + CreateMenu "{{menu_file_ideoptions}}",MENUOPTIONS,file + CreateMenu "{{menu_file_projectmanager}}",MENUPROJECTMANAGER,file + CreateMenu "",0,file + CreateMenu "{{menu_file_print}}",MENUPRINT,file,KEY_P,MENUMOD +?Not MacOS + CreateMenu "",0,file + CreateMenu "{{menu_file_exit}}",MENUQUIT,file +? + edit=CreateMenu("{{menu_edit}}",0,menu) + CreateMenu "{{menu_edit_undo}}",MENUUNDO,edit,KEY_Z,MENUMOD +?MacOS + CreateMenu "{{menu_edit_redo}}",MENUREDO,edit,KEY_Z,MENUMOD|MODIFIER_SHIFT +?Not MacOS + CreateMenu "{{menu_edit_redo}}",MENUREDO,edit,KEY_Y,MENUMOD +? + CreateMenu "",0,edit + CreateMenu "{{menu_edit_cut}}",MENUCUT,edit,KEY_X,MENUMOD + CreateMenu "{{menu_edit_copy}}",MENUCOPY,edit,KEY_C,MENUMOD + CreateMenu "{{menu_edit_paste}}",MENUPASTE,edit,KEY_V,MENUMOD + CreateMenu "",0,edit + CreateMenu "{{menu_edit_selectall}}",MENUSELECTALL,edit,KEY_A,MENUMOD + CreateMenu "",0,edit + CreateMenu "{{menu_edit_blockindent}}",MENUINDENT,edit,KEY_CLOSEBRACKET,MENUMOD + CreateMenu "{{menu_edit_blockoutdent}}",MENUOUTDENT,edit,KEY_OPENBRACKET,MENUMOD + CreateMenu "",0,edit + CreateMenu "{{menu_edit_find}}",MENUFIND,edit,KEY_F,MENUMOD +?MacOS + CreateMenu "{{menu_edit_findnext}}",MENUFINDNEXT,edit,KEY_G,MENUMOD + CreateMenu "{{menu_edit_replace}}",MENUREPLACE,edit,KEY_H,MENUMOD + CreateMenu "{{menu_edit_gotoline}}",MENUGOTO,edit,KEY_L,MENUMOD +?Not MacOS + CreateMenu "{{menu_edit_findnext}}",MENUFINDNEXT,edit,KEY_F3 + CreateMenu "{{menu_edit_replace}}",MENUREPLACE,edit,KEY_H,MENUMOD + CreateMenu "{{menu_edit_gotoline}}",MENUGOTO,edit,KEY_G,MENUMOD +? + CreateMenu "",0,edit + CreateMenu "{{menu_edit_findinfiles}}",MENUFINDINFILES,edit,KEY_F,MENUMOD|MODIFIER_SHIFT + + program=CreateMenu("{{menu_program}}",0,menu) + CreateMenu "{{menu_program_build}}",MENUBUILD,program,KEY_B,MENUMOD + CreateMenu "{{menu_program_buildandrun}}",MENURUN,program,KEY_R,MENUMOD + CreateMenu "{{menu_program_commandline}}",MENUCOMMANDLINE,program + CreateMenu "",0,program + CreateMenu "{{menu_program_step}}",MENUSTEP,program,KEY_F9 + CreateMenu "{{menu_program_stepin}}",MENUSTEPIN,program,KEY_F10 + CreateMenu "{{menu_program_stepout}}",MENUSTEPOUT,program,KEY_F11 + CreateMenu "{{menu_program_terminate}}",MENUSTOP,program + buildoptions=CreateMenu("{{menu_program_buildoptions}}",0,program) + quickenable=CreateMenu("{{menu_program_buildoptions_quick}}",MENUQUICKENABLED,buildoptions) + debugenable=CreateMenu("{{menu_program_buildoptions_debug}}",MENUDEBUGENABLED,buildoptions) + If (FileType( BlitzMaxPath()+"/mod/brl.mod/blitz.mod/blitz_gc_ms.c" )=FILETYPE_FILE) .. + Or (FileType( BlitzMaxpath()+"/mod/brl.mod/blitz.mod/bdwgc" )=FILETYPE_DIR) + threadedenable=CreateMenu("{{menu_program_buildoptions_threaded}}",MENUTHREADEDENABLED,buildoptions) + EndIf + guienable=CreateMenu("{{menu_program_buildoptions_guiapp}}",MENUGUIENABLED,buildoptions) + CreateMenu "",0,program + CreateMenu "{{menu_program_lockbuildfile}}",MENULOCKBUILD,program + CreateMenu "{{menu_program_unlockbuildfile}}",MENUUNLOCKBUILD,program + CreateMenu "",0,program + 'syncmods=CreateMenu("{{menu_program_syncmods}}",MENUSYNCMODS,program) + 'CreateMenu "",0,program + buildmods=CreateMenu("{{menu_program_buildmods}}",MENUBUILDMODULES,program,KEY_D,MENUMOD) + buildallmods=CreateMenu("{{menu_program_rebuildallmods}}",MENUBUILDALLMODULES,program) + docmods=CreateMenu("{{menu_program_rebuilddocs}}",MENUDOCMODS,program) + + help=CreateMenu("{{menu_help}}",0,menu) + CreateMenu "{{menu_help_home}}",MENUHOME,help + CreateMenu "{{menu_help_back}}",MENUBACK,help + CreateMenu "{{menu_help_forward}}",MENUFORWARD,help + CreateMenu "{{menu_help_quickhelp}}",MENUQUICKHELP,help,KEY_F1 + CreateMenu "{{menu_help_aboutmaxide}}",MENUABOUT,help + + If quickenabled CheckMenu quickenable + If debugenabled CheckMenu debugenable + If threadedenabled CheckMenu threadedenable + If guienabled CheckMenu guienable + +?Win32 + Local mingw$=getenv_("MINGW") + If Not mingw + DisableMenu buildmods + DisableMenu buildallmods + EndIf +? +' If is_demo +' DisableMenu syncmods +' EndIf + + RefreshRecentFiles + UpdateWindowMenu window + End Method + + Method RunCode() + If mode=DEBUGMODE And debugtree.cancontinue + output.Go() + Return + EndIf + output.Stop() + SaveAll() + If lockedpanel + lockedpanel.invoke TOOLRUN + Else + activepanel.invoke TOOLRUN + EndIf + End Method + + Method BuildCode() + output.Stop() + SaveAll() + If lockedpanel + lockedpanel.invoke TOOLBUILD + Else + activepanel.invoke TOOLBUILD + EndIf + End Method + + + Method AddEventHotKey(key,mods,id,data) + SetHotKeyEvent key,mods,CreateEvent(id,Null,data) + End Method + + Method InitHotkeys() + AddEventHotKey KEY_F5,MODIFIER_NONE,EVENT_MENUACTION,MENURUN + AddEventHotKey KEY_F7,MODIFIER_NONE,EVENT_MENUACTION,MENUBUILD + End Method + + Method SaveAll() + For Local panel:TToolPanel = EachIn panels + panel.invoke TOOLQUICKSAVE + Next + End Method + + Method Restart() + If Confirm(LocalizeString("{{request_restart}}")) + Quit + EndIf + End Method + + Method RefreshAll() +' hide/show toolbar + If options.showtoolbar Then ShowGadget toolbar Else HideGadget toolbar +' refresh panels + For Local panel:TToolPanel = EachIn panels + panel.invoke TOOLREFRESH + Next +' refresh navbar + navbar.invoke TOOLREFRESH + End Method + + Method SnapshotWindow() + If WindowMaximized(window) + winmax=True + Else + If Not WindowMinimized(window) + winmax=False + winsize.x=GadgetX(window) + winsize.y=GadgetY(window) + winsize.w=GadgetWidth(window) + winsize.h=GadgetHeight(window) + EndIf + EndIf + options.showtoolbar = Not GadgetHidden(toolbar) + End Method + + Method OnMenu(menu,extra:Object=Null) + Local index + + Local tool:TTool = TTool(extra) + If tool + tool.invoke(TOOLMENU,""+menu) + Return + EndIf + + Select menu + Case MENUNEW + OpenSource "" + Case MENUOPEN + OpenSource "." + Case MENUCLOSE + currentpanel.invoke TOOLCLOSE + Case MENUCLOSEALL + CloseAll True + Case MENUCLOSEOTHERS + CloseAll True, False + Case MENUSAVE + currentpanel.invoke TOOLSAVE + Case MENUSAVEAS + currentpanel.invoke TOOLSAVEAS + Case MENUSAVEALL + SaveAll() + Case MENUPRINT + currentpanel.invoke TOOLPRINT + Case MENUQUIT + Quit() + + Case MENUGOTO + gotoreq.Show() + Case MENUFIND + currentpanel.invoke TOOLFIND + Case MENUFINDNEXT + currentpanel.invoke TOOLFINDNEXT + Case MENUREPLACE + replacereq.Show() + + Case MENUUNDO currentpanel.invoke TOOLUNDO + Case MENUREDO currentpanel.invoke TOOLREDO + + Case MENUCUT currentpanel.invoke TOOLCUT + Case MENUCOPY currentpanel.invoke TOOLCOPY + Case MENUPASTE currentpanel.invoke TOOLPASTE + Case MENUSELECTALL currentpanel.invoke TOOLSELECTALL + + Case MENUBUILD + BuildCode() + Case MENURUN + RunCode() + + Case MENUBUILDMODULES + If CheckDemo() BuildModules False + Case MENUBUILDALLMODULES + If CheckDemo() BuildModules True + 'Case MENUSYNCMODS + ' If CheckDemo() And CloseAll(False) syncmodsreq.Show + Case MENUDOCMODS + If CheckDemo() And CloseAll(False) DocMods + Case MENUTRIGGERDOCMODS + DocMods() + Case MENUTRIGGERSYNCDOCS + SyncDocs() + + Case MENUSTEP If output output.StepOver() + Case MENUSTEPIN If output output.StepIn() + Case MENUSTEPOUT If output output.StepOut() + Case MENUSTOP If output output.Stop() + + Case MENULOCKBUILD + activepanel.invoke TOOLLOCK + Case MENUUNLOCKBUILD + If lockedpanel lockedpanel.invoke TOOLUNLOCK + + Case MENUCOMMANDLINE cmdlinereq.Show + + Case MENUQUICKENABLED + If quickenabled + quickenabled=False + UncheckMenu quickenable + Else + quickenabled=True + CheckMenu quickenable + EndIf + UpdateWindowMenu window + + Case MENUDEBUGENABLED + If debugenabled + debugenabled=False + UncheckMenu debugenable + Else + debugenabled=True + CheckMenu debugenable + EndIf + UpdateWindowMenu window + + Case MENUTHREADEDENABLED + If threadedenabled + threadedenabled=False + UncheckMenu threadedenable + Else + threadedenabled=True + CheckMenu threadedenable + EndIf + UpdateWindowMenu window + + Case MENUGUIENABLED + If guienabled + guienabled=False + UncheckMenu guienable + Else + guienabled=True + CheckMenu guienable + EndIf + UpdateWindowMenu window + + Case MENUIMPORTBB + ImportBB + + Case MENUFINDINFILES + If activepanel Then searchreq.ShowWithPath( ExtractDir(activepanel.path) ) Else searchreq.Show() + + Case MENUPROJECTMANAGER + projectreq.Open projects + Case MENUSHOWCONSOLE + If output Then output.Open() + + Case MENUOPTIONS + options.Show() + + Case MENUNEXT + If Not currentpanel Return + index=currentpanel.index+1 + If index=panels.length index=0 + SelectPanel panels[index] + + Case MENUPREV + If Not currentpanel Return + index=currentpanel.index-1 + If index<0 index=panels.length-1 + SelectPanel panels[index] + + Case MENUQUICKHELP + currentpanel.invoke TOOLHELP + + Case MENUHOME + helppanel.Home() + SelectPanel helppanel + Case MENUBACK + helppanel.Back() + SelectPanel helppanel + Case MENUFORWARD + helppanel.Forward() + SelectPanel helppanel + Case MENUABOUT + aboutreq.Show() + 'Notify (ABOUT.Replace( "{bcc_version}",BCC_VERSION )) + Case MENUINDENT + currentpanel.invoke TOOLINDENT + Case MENUOUTDENT + currentpanel.invoke TOOLOUTDENT + + Case MENUNEWVIEW + navbar.invoke TOOLNEWVIEW + + End Select + + If menu>=MENURECENT + Local f:String = String(recentfiles.ValueAtIndex(menu-MENURECENT)) + If f$ OpenSource f$ + EndIf + End Method + + Method poll() + + Local src:TGadget + Local event = WaitEvent() + + If Not activerequesters.IsEmpty() + Select event + Case EVENT_MENUACTION + src = ActiveGadget() + If src And (GadgetClass(src) = GADGET_TEXTFIELD) Then + Select EventData() + Case MENUSELECTALL + ActivateGadget(src) + Case MENUCOPY + GadgetCopy(src) + Case MENUPASTE + GadgetPaste(src) + Case MENUCUT + GadgetCut(src) + EndSelect + Return + EndIf + src = Null + Case EVENT_MOUSEENTER,EVENT_MOUSELEAVE,EVENT_GADGETLOSTFOCUS + Return + End Select + 'DebugLog CurrentEvent.ToString() + For Local activerequester:TRequester = EachIn activerequesters + If activerequester.Poll() Then Return + Next + EndIf + + For Local handler:TEventHandler = EachIn eventhandlers + handler.OnEvent() + Next + + src = TGadget(EventSource()) + + Select event + Case EVENT_GADGETACTION + Select EventSource() + Case toolbar + Select EventData() + Case TB_NEW OpenSource "" + Case TB_OPEN OpenSource "." + Case TB_CLOSE currentpanel.invoke TOOLCLOSE + Case TB_SAVE currentpanel.invoke TOOLSAVE + Case TB_CUT currentpanel.invoke TOOLCUT + Case TB_COPY currentpanel.invoke TOOLCOPY + Case TB_PASTE currentpanel.invoke TOOLPASTE + Case TB_FIND currentpanel.invoke TOOLFIND + Case TB_BUILD BuildCode + Case TB_BUILDRUN RunCode + Case TB_STEP If output output.stepover + Case TB_STEPIN If output output.stepin + Case TB_STEPOUT If output output.stepout + Case TB_STOP If output output.Stop + Case TB_HOME helppanel.Home;SelectPanel helppanel + Case TB_BACK helppanel.Back;SelectPanel helppanel + Case TB_FORWARDS helppanel.Forward;SelectPanel helppanel + End Select + + Case tabbar + Local index = EventData() + If index>=0 And index