فهرست منبع

Tweaks to doc system.

Mark Sibly 9 سال پیش
والد
کامیت
f58027819d
5فایلهای تغییر یافته به همراه359 افزوده شده و 292 حذف شده
  1. 222 183
      src/mx2new/docsmaker.monkey2
  2. 117 84
      src/mx2new/htmldocsmaker.monkey2
  3. 1 1
      src/mx2new/mx2.monkey2
  4. 18 24
      src/mx2new/mx2cc.monkey2
  5. 1 0
      src/mx2new/parser.monkey2

+ 222 - 183
src/mx2new/docsmaker.monkey2

@@ -1,77 +1,22 @@
 
 Namespace mx2.docs
 
-Class DocsMaker
+Class MarkdownBuffer
 
-Protected
-	
-	Field _module:Module
-	
-	Field _scope:Scope
+	Alias LinkResolver:String( link:String )
 
-	Field _pagesDir:String			'module/docs
-	Field _pageTemplate:String
-	
-	Field _buf:=New StringStack
-	Field _params:=New StringStack
-	Field _return:String
-	
-	Function JsonEscape:String( str:String )
-		str=str.Replace( "\","\\" )
-		str=str.Replace( "~q","\~q" )
-		str=str.Replace( "~n","\n" )
-		str=str.Replace( "~r","\r" )
-		str=str.Replace( "~t","\t" )
-		Return "~q"+str+"~q"
-	End
-	
-	Function FindSpc:Int( str:String )
-	
-		For Local i:=0 Until str.Length
-			If str[i]<=32 Return i
-		Next
-		
-		Return str.Length
-	End
-	
-	Function FindChar:Int( str:String )
-	
-		For Local i:=0 Until str.Length
-			If str[i]>32 Return i
-		Next
-		
-		Return -1
-	End
-	
-	Method EmitBr()
-		_buf.Push( "" )
+	Method New( linkResolver:LinkResolver=Null )
+		_linkResolver=linkResolver
 	End
+
+	Method Emit( markdown:String )
 	
-	Method ReplaceLinks:String( line:String )
-		Repeat
-			Local i0:=line.Find( "[[" )
-			If i0=-1 Return line
-			Local i1:=line.Find( "]]",i0+2 )
-			If i1=-1 Return line
-			Local path:=line.Slice( i0+2,i1 )
-			Local link:=ResolveLink( path,_scope )
-			If Not link
-				Print "Makedocs error: Can't resolve link '"+path+"'"
-				link=path
-			Endif
-			line=line.Slice( 0,i0 )+link+line.Slice( i1+2 )
-		Forever
-		Return line
-	End
-	
-	Method Emit( docs:String )
-	
-		If Not docs.Contains( "~n" )
-			_buf.Push( ReplaceLinks( docs ) )
+		If Not markdown.Contains( "~n" )
+			_buf.Push( ReplaceLinks( markdown ) )
 			Return
 		Endif
 		
-		Local lines:=docs.Split( "~n" )
+		Local lines:=markdown.Split( "~n" )
 		
 		For Local i:=0 Until lines.Length
 		
@@ -115,11 +60,13 @@ Protected
 					_buf.Push( "```" )
 					
 				Case "see"
-					'TODO
+				
 					Continue
 				
 				Default
-					Print "Makedocs: unrecognized '"+lines[i]+"'"
+				
+					Print "MarkdownBuffer: unrecognized '"+lines[i]+"'"
+					
 				End
 
 				Continue
@@ -128,34 +75,37 @@ Protected
 			_buf.Push( ReplaceLinks( line ) )
 			
 		Next
+	
 	End
 	
-	Method FlushParams()
+	Method EmitBr()
+	
+		_buf.Push( "" )
+	End
+	
+	Method Flush:String()
 
-		If Not _params.Length Return
-		
-		EmitBr()
-		Emit( "| Parameters |    |" )
-		Emit( "|:-----------|:---|" )
-		
-		For Local p:=Eachin _params
+		If _params.Length	
 		
-			Local i:=FindSpc( p )
-			Local id:=p.Slice( 0,i )
-			p=p.Slice( i ).Trim()
+			EmitBr()
+			Emit( "| Parameters |    |" )
+			Emit( "|:-----------|:---|" )
 			
-			If Not id Or Not p Continue
+			For Local p:=Eachin _params
 			
-			Emit( "| `"+id+"` | "+p+" |" )
-		Next
+				Local i:=FindSpc( p )
+				Local id:=p.Slice( 0,i )
+				p=p.Slice( i ).Trim()
+				
+				If Not id Or Not p Continue
+				
+				Emit( "| `"+id+"` | "+p+" |" )
+			Next
+			
+			_params.Clear()
+			
+		Endif
 		
-		_params.Clear()
-	End
-	
-	Method Flush:String()
-	
-		FlushParams()
-	
 		Local markdown:=_buf.Join( "~n" ).Trim()+"~n"
 		
 		_buf.Clear()
@@ -165,16 +115,91 @@ Protected
 		Return docs
 	End
 	
+	Private
+	
+	Field _linkResolver:LinkResolver
+	Field _buf:=New StringStack
+	Field _params:=New StringStack
+	Field _return:String
+	
+	Method FindSpc:Int( str:String )
+		For Local i:=0 Until str.Length
+			If str[i]<=32 Return i
+		Next
+		Return str.Length
+	End
+
+	Method FindChar:Int( str:String )
+		For Local i:=0 Until str.Length
+			If str[i]>32 Return i
+		Next
+		Return -1
+	End
+	
+	Method ReplaceLinks:String( line:String )
+	
+		Repeat
+			Local i0:=line.Find( "[[" )
+			If i0=-1 Return line
+			
+			Local i1:=line.Find( "]]",i0+2 )
+			If i1=-1 Return line
+			
+			Local path:=line.Slice( i0+2,i1 )
+			Local link:=path
+			
+			If _linkResolver<>Null
+				link=_linkResolver( path )
+				If Not link
+					Print "Makedocs error: Can't resolve link '"+path+"'"
+					link=path
+				Endif
+			Endif
+			
+			line=line.Slice( 0,i0 )+link+line.Slice( i1+2 )
+		Forever
+		
+		Return line
+	End
+
+End
+
+Class DocsMaker
+
+	Protected
+	
+	Field _module:Module
+	
+	Field _linkScope:Scope
+
+	Field _pagesDir:String			'module/docs
+	
+	Field _pageTemplate:String
+	
+	Field _md:MarkdownBuffer
+	
+	Method New()
+	
+		_md=New MarkdownBuffer( Lambda:String( link:String )
+			Return ResolveLink( link,_linkScope )
+		End )
+		
+	End
+	
 	Method Esc:String( id:String )
 		id=id.Replace( "_","\_" )
+		id=id.Replace( "<","\<" )
+		id=id.Replace( ">","\>" )
 		Return id
 	End	
 	
-	Method DeclSlug:String( decl:Decl,scope:Scope )
+	Method DeclPath:String( decl:Decl,scope:Scope )
+	
 		Local ident:=decl.ident.Replace( "@","" )
 		If Not IsIdent( ident[0] ) ident=OpSym( ident )
 		
 		Local slug:=scope.Name+"."+ident
+		
 		Repeat
 			Local i:=slug.Find( "<" )
 			If i=-1 Exit
@@ -182,72 +207,76 @@ Protected
 			If i2=-1 Exit
 			slug=slug.Slice( 0,i )+slug.Slice( i2+1 )
 		Forever
-		'slug=slug.Replace( ".","-" )
-		Return slug
-	End
-	
-	Method NamespaceSlug:String( nmspace:NamespaceScope )
-		Local slug:=nmspace.Name
-		'slug=slug.Replace( ".","-" )
+		
 		Return slug
 	End
 	
-	Method DeclPage:String( decl:Decl,scope:Scope )
-	
-		Return DeclSlug( decl,scope )
-	End
-	
-	Method NamespacePage:String( nmspace:NamespaceScope )
+	Method NamespacePath:String( nmspace:NamespaceScope )
 	
-		Return NamespaceSlug( nmspace )
+		Return nmspace.Name
 	End
 	
-	Method MakeLink:String( text:String,url:String )
+	Method DeclSlug:String( decl:Decl,scope:Scope )
+
+		Local module:=scope.FindFile().fdecl.module.name
 
-		Return "<a href='"+url+"'>"+text+"</a>"
+		Local slug:=module+":"+DeclPath( decl,scope ).Replace( ".","-" )
+		
+		Return slug
 	End
 	
-	Method MakeLink:String( text:String,module:String,page:String )
+	Method NamespaceSlug:String( nmspace:NamespaceScope )
 	
-		Local url:=module+":"+page
+		Local slug:=_module.name+":"+NamespacePath( nmspace ).Replace( ".","-" )
 		
-		Return "<a href=~qjavascript:void('"+url+"')~q onclick=~qdocsLinkClicked('"+url+"')~q>"+text+"</a>"
+		Return slug
 	End
 	
 	Method MakeLink:String( text:String,decl:Decl,scope:Scope )
 	
-		Local module:=scope.FindFile().fdecl.module.name
-		Local page:=DeclPage( decl,scope )
+		Local slug:=DeclSlug( decl,scope )
 		
-		Return MakeLink( text,module,page )
+		Return "<a href=~qjavascript:void('"+slug+"')~q onclick=~qdocsLinkClicked('"+slug+"')~q>"+text+"</a>"
 	End
 	
+	Method MakeLink:String( text:String,nmspace:NamespaceScope )
+	
+		Local slug:=NamespaceSlug( nmspace )
+		
+		Return "<a href=~qjavascript:void('"+slug+"')~q onclick=~qdocsLinkClicked('"+slug+"')~q>"+text+"</a>"
+	End
+
 	Method ResolveLink:String( path:String,scope:Scope )
 	
 		Local i0:=0
 		
+		Local tpath:=""
+		
 		Repeat
 		
 			Local i1:=path.Find( ".",i0 )
-			If i1=-1	'find 'leaf'
+			If i1=-1
 			
 				Local id:=path.Slice( i0 )
-'				Print "Finding node "+id+" in "+scope.Name
 
 				Local node:=scope.FindNode( id )
-				If Not node Return ""
+				If Not node
+					Return path
+				Endif
+				
+				tpath+=id
 				
 				Local vvar:=Cast<VarValue>( node )
-				If vvar Return MakeLink( id,vvar.vdecl,vvar.scope )
+				If vvar Return MakeLink( tpath,vvar.vdecl,vvar.scope )
 				
 				Local flist:=Cast<FuncList>( node )
-				If flist Return MakeLink( id,flist.funcs[0].fdecl,flist.funcs[0].scope )
+				If flist Return MakeLink( tpath,flist.funcs[0].fdecl,flist.funcs[0].scope )
 				
 				Local etype:=TCast<EnumType>( node )
-				If etype Return MakeLink( id,etype.edecl,etype.scope.outer )
+				If etype Return MakeLink( tpath,etype.edecl,etype.scope.outer )
 				
 				Local ctype:=TCast<ClassType>( node )
-				If ctype Return MakeLink( id,ctype.cdecl,ctype.scope.outer )
+				If ctype Return MakeLink( tpath,ctype.cdecl,ctype.scope.outer )
 				
 				Return ""
 			Endif
@@ -255,8 +284,6 @@ Protected
 			Local id:=path.Slice( i0,i1 )
 			i0=i1+1
 			
-'			Print "Finding type "+id+" in "+scope.Name
-
 			Local type:Type
 			If scope
 				Try
@@ -264,7 +291,7 @@ Protected
 				Catch ex:SemantEx
 					Print "Exception!"
 				End
-			Else
+			Else If Not tpath
 				For Local fscope:=Eachin _module.fileScopes
 					If id<>fscope.nmspace.ntype.ident Continue
 					type=fscope.nmspace.ntype
@@ -272,7 +299,11 @@ Protected
 				Next
 			Endif
 
-			If Not type Return ""
+			If Not type 
+				Return path
+			Endif
+			
+			tpath+=id+"."
 			
 			Local ntype:=TCast<NamespaceType>( type )
 			If ntype
@@ -283,7 +314,7 @@ Protected
 			Local etype:=TCast<EnumType>( type )
 			If etype
 				'stop at enum!
-				Return MakeLink( id+"."+path.Slice( i0 ),etype.edecl,etype.scope.outer )
+				Return MakeLink( tpath+"."+path.Slice( i0 ),etype.edecl,etype.scope.outer )
 			Endif
 			
 			Local ctype:=TCast<ClassType>( type )
@@ -353,7 +384,8 @@ Protected
 	Method DeclDesc:String( decl:Decl )
 		Local desc:=decl.docs
 		Local i:=desc.Find( "~n" )
-		If i<>-1 Return desc.Slice( 0,i )
+		If i<>-1 desc=desc.Slice( 0,i )
+'		desc=Esc( desc )
 		Return desc
 	End
 	
@@ -450,13 +482,13 @@ Protected
 	
 	Method EmitHeader( decl:Decl,scope:Scope )
 		Local fscope:=scope.FindFile()
-		Local module:=fscope.fdecl.module.name
-		Local nmspace:=fscope.nmspace.Name
-		Emit( "_Module: &lt;"+module+"&gt;_  " )
-		Emit( "_Namespace:_ <em>"+MakeLink( nmspace,module,NamespacePage( fscope.nmspace ) )+"</em>" )
-		EmitBr()
-		Emit( "#### "+DeclName( decl,scope ) )
-		EmitBr()
+		Local nmspace:=fscope.nmspace
+		Local module:=fscope.fdecl.module
+		_md.Emit( "_Module: &lt;"+module.name+"&gt;_  " )
+		_md.Emit( "_Namespace:_ _"+MakeLink( NamespacePath( nmspace ),nmspace )+"_" )
+		_md.EmitBr()
+		_md.Emit( "#### "+DeclName( decl,scope ) )
+		_md.EmitBr()
 	End
 	
 	Method DocsHidden:Bool( decl:Decl )
@@ -478,12 +510,12 @@ Protected
 				
 				If init
 					init=False
-					EmitBr()
-					Emit( "| Aliases | &nbsp; |" )
-					Emit( "|:---|:---" )
+					_md.EmitBr()
+					_md.Emit( "| Aliases | &nbsp; |" )
+					_md.Emit( "|:---|:---" )
 				Endif
 				
-				Emit( "| "+DeclIdent( decl,atype.scope )+" | "+DeclDesc( decl )+" |" )
+				_md.Emit( "| "+DeclIdent( decl,atype.scope )+" | "+DeclDesc( decl )+" |" )
 				Continue
 			Endif
 				
@@ -498,12 +530,12 @@ Protected
 				If init
 					init=False
 					Local kinds:=kind.Capitalize() + (kind="class" ? "es" Else "s")
-					EmitBr()
-					Emit( "| "+kinds+" | |" )
-					Emit( "|:---|:---|" )
+					_md.EmitBr()
+					_md.Emit( "| "+kinds+" | |" )
+					_md.Emit( "|:---|:---|" )
 				Endif
 				
-				Emit( "| "+DeclIdent( decl,ctype.scope.outer )+" | "+DeclDesc( decl )+" |" )
+				_md.Emit( "| "+DeclIdent( decl,ctype.scope.outer )+" | "+DeclDesc( decl )+" |" )
 				Continue
 			Endif
 			
@@ -516,12 +548,12 @@ Protected
 				
 				If init
 					init=False
-					EmitBr()
-					Emit( "| Enums | |" )
-					Emit( "|:---|:---|" )
+					_md.EmitBr()
+					_md.Emit( "| Enums | |" )
+					_md.Emit( "|:---|:---|" )
 				Endif
 
-				Emit( "| "+DeclIdent( decl,etype.scope.outer )+" | "+DeclDesc( decl )+" |" )
+				_md.Emit( "| "+DeclIdent( decl,etype.scope.outer )+" | "+DeclDesc( decl )+" |" )
 				Continue
 			Endif
 
@@ -534,12 +566,12 @@ Protected
 
 				If init
 					init=False
-					EmitBr()
-					Emit( "| "+kind.Capitalize()+"s | |" )
-					Emit( "|:---|:---|" )
+					_md.EmitBr()
+					_md.Emit( "| "+kind.Capitalize()+"s | |" )
+					_md.Emit( "|:---|:---|" )
 				Endif
 
-				Emit( "| "+DeclIdent( decl,vvar.scope )+" | "+DeclDesc( decl )+" |" )
+				_md.Emit( "| "+DeclIdent( decl,vvar.scope )+" | "+DeclDesc( decl )+" |" )
 				Continue
 			Endif
 			
@@ -552,12 +584,12 @@ Protected
 				
 				If init
 					init=False
-					EmitBr()
-					Emit( "| Properties | |" )
-					Emit( "|:---|:---|" )
+					_md.EmitBr()
+					_md.Emit( "| Properties | |" )
+					_md.Emit( "|:---|:---|" )
 				Endif
 
-				Emit( "| "+DeclIdent( decl,plist.scope )+" | "+DeclDesc( decl )+" |" )
+				_md.Emit( "| "+DeclIdent( decl,plist.scope )+" | "+DeclDesc( decl )+" |" )
 				Continue
 			Endif
 		
@@ -580,12 +612,12 @@ Protected
 					
 					If init
 						init=False
-						EmitBr()
-						Emit( "| "+kind.Capitalize()+"s | |" )
-						Emit( "|:---|:---|" )
+						_md.EmitBr()
+						_md.Emit( "| "+kind.Capitalize()+"s | |" )
+						_md.Emit( "|:---|:---|" )
 					Endif
 					
-					Emit( "| "+DeclIdent( decl,func.scope )+" | "+DeclDesc( decl )+" |" )
+					_md.Emit( "| "+DeclIdent( decl,func.scope )+" | "+DeclDesc( decl )+" |" )
 					Exit
 					
 				Next
@@ -596,12 +628,13 @@ Protected
 
 	End
 	
+	#rem
 	Method MakeNamespaceDocs:String( nmspace:NamespaceScope )
 	
-		_scope=nmspace
+		_linkScope=nmspace
 	
-		Emit( "_Module: &lt;"+_module.name+"&gt;_  " )
-		Emit( "_Namespace: "+nmspace.Name+"_" )
+		_md.Emit( "_Module: &lt;"+_module.name+"&gt;_  " )
+		_md.Emit( "_Namespace: "+nmspace.Name+"_" )
 		
 		EmitMembers( "alias",nmspace,True )
 		EmitMembers( "enum",nmspace,True )
@@ -612,23 +645,26 @@ Protected
 		EmitMembers( "global",nmspace,True )
 		EmitMembers( "function",nmspace,True )
 		
-		Return Flush()
+		_md.Emit( _namespaceDocs[nmspace.ntype.ident] )
+		
+		Return _md.Flush()
 	End
+	#end
 	
 	Method MakeAliasDocs:String( atype:AliasType )
 		Local decl:=atype.adecl
 		
 		If DocsHidden( decl ) Return ""
 		
-		_scope=atype.scope
+		_linkScope=atype.scope
 		
 		EmitHeader( decl,atype.scope )
 		
-		Emit( "##### Alias "+DeclIdent( decl,True )+" : "+TypeName( atype._alias,atype.scope ) )
+		_md.Emit( "##### Alias "+DeclIdent( decl,True )+" : "+TypeName( atype._alias,atype.scope ) )
 		
-		Emit( decl.docs )
+		_md.Emit( decl.docs )
 		
-		Return Flush()
+		Return _md.Flush()
 	End
 	
 	Method MakeEnumDocs:String( etype:EnumType )
@@ -636,15 +672,15 @@ Protected
 		
 		If DocsHidden( decl ) Return ""
 		
-		_scope=etype.scope.outer
+		_linkScope=etype.scope.outer
 
 		EmitHeader( decl,etype.scope.outer )
 		
-		Emit( "##### Enum "+DeclIdent( decl ) )
+		_md.Emit( "##### Enum "+DeclIdent( decl ) )
 		
-		Emit( decl.docs )
+		_md.Emit( decl.docs )
 		
-		Return Flush()
+		Return _md.Flush()
 	End
 	
 	Method MakeClassDocs:String( ctype:ClassType )
@@ -653,7 +689,7 @@ Protected
 		
 		If DocsHidden( decl ) Return ""
 		
-		_scope=ctype.scope	'.outer
+		_linkScope=ctype.scope	'.outer
 		
 		EmitHeader( decl,ctype.scope.outer )
 		
@@ -689,9 +725,9 @@ Protected
 			mods+=" Final"
 		Endif
 		
-		Emit( "##### "+decl.kind.Capitalize()+" "+DeclIdent( decl,True )+xtends+implments+mods )
+		_md.Emit( "##### "+decl.kind.Capitalize()+" "+DeclIdent( decl,True )+xtends+implments+mods )
 		
-		Emit( decl.docs )
+		_md.Emit( decl.docs )
 		
 		For Local inh:=0 Until 1
 			EmitMembers( "alias",ctype.scope,inh )
@@ -709,7 +745,7 @@ Protected
 			EmitMembers( "function",ctype.scope,inh )
 		End
 		
-		Return Flush()
+		Return _md.Flush()
 	End
 	
 	Method MakeVarDocs:String( vvar:VarValue )
@@ -718,15 +754,15 @@ Protected
 		
 		If DocsHidden( decl ) Return ""
 		
-		_scope=vvar.scope
+		_linkScope=vvar.scope
 		
 		EmitHeader( decl,vvar.scope )
 		
-		Emit( "##### "+decl.kind.Capitalize()+" "+DeclIdent( decl )+" : "+TypeName( vvar.type,vvar.scope ) )
+		_md.Emit( "##### "+decl.kind.Capitalize()+" "+DeclIdent( decl )+" : "+TypeName( vvar.type,vvar.scope ) )
 		
-		Emit( decl.docs )
+		_md.Emit( decl.docs )
 		
-		Return Flush()
+		Return _md.Flush()
 	End
 		
 	Method MakePropertyDocs:String( plist:PropertyList )
@@ -742,15 +778,15 @@ Protected
 		
 '		Local fdecl:=func.fdecl
 
-		_scope=func.scope
+		_linkScope=func.scope
 		
 		EmitHeader( decl,func.scope )
 		
-		Emit( "##### Property "+DeclIdent( decl )+" : "+TypeName( type,func.scope ) )
+		_md.Emit( "##### Property "+DeclIdent( decl )+" : "+TypeName( type,func.scope ) )
 		
-		Emit( decl.docs )
+		_md.Emit( decl.docs )
 		
-		Return Flush()
+		Return _md.Flush()
 	End
 	
 	Method MakeFuncDocs:String( flist:FuncList,kind:String )
@@ -772,7 +808,7 @@ Protected
 				Continue
 			Endif
 			
-			_scope=func.scope
+			_linkScope=func.scope
 			
 			If Not docs
 				docs=New StringStack
@@ -796,17 +832,20 @@ Protected
 			Next
 			params=params.Slice( 3 )
 			
-			Emit( "##### "+tkind+DeclIdent( decl,True )+" : "+TypeName( func.ftype.retType,func.scope )+" ( "+params+" ) " )
+			_md.Emit( "##### "+tkind+DeclIdent( decl,True )+" : "+TypeName( func.ftype.retType,func.scope )+" ( "+params+" ) " )
 
 		Next
 		
-		If Not docs Return ""
+		If Not docs 
+			_md.Flush()
+			Return ""
+		Endif
 		
 		For Local doc:=Eachin docs
-			Emit( doc )
+			_md.Emit( doc )
 		Next
 		
-		Return Flush()
+		Return _md.Flush()
 	End
 	
 End

+ 117 - 84
src/mx2new/htmldocsmaker.monkey2

@@ -3,14 +3,63 @@ Namespace mx2.docs
 
 Const PAGES_DIR:="docs/__PAGES__/"
 
+Class JsonBuffer
+
+	Method Emit( json:String )
+	
+		If json.StartsWith( "}" ) Or json.StartsWith( "]" )
+
+			_indent=_indent.Slice( 0,-2 )
+			_sep=False
+			
+			If _blks.Pop()=_buf.Length
+				_buf.Resize( _buf.Length-1 )
+				If _buf.Length
+					Local t:=_buf.Top
+					If Not (t.EndsWith( "{" ) Or t.EndsWith( "[" )) _sep=True
+				Endif
+				Return
+			Endif
+
+		Endif
+	
+		If _sep json=","+json
+		_buf.Push( _indent+json )
+	
+		If json.EndsWith( "{" ) Or json.EndsWith( "[" ) 
+
+			_blks.Push( _buf.Length )
+
+			_indent+="  "
+			_sep=False
+
+			Return
+		Endif
+
+		_sep=True
+	
+	End
+	
+	Method Flush:String()
+		Local json:=_buf.Join( "~n" )
+		_buf.Clear()
+		Return json
+	End
+	
+	Private
+
+	Field _buf:=New StringStack
+	Field _blks:=New IntStack
+	Field _indent:String
+	Field _sep:Bool
+
+End
+
 Class HtmlDocsMaker Extends DocsMaker
 
 	Method MakeDocs:String( module:Module )
 	
 		_module=module
-		_buf.Clear()
-		_indent=""
-		_sep=False
 		
 		_pagesDir=_module.baseDir+PAGES_DIR
 		_pageTemplate=stringio.LoadString( "docs/modules_page_template.html" )
@@ -20,7 +69,7 @@ Class HtmlDocsMaker Extends DocsMaker
 		
 		EmitModule()
 		
-		Local tree:=_buf.Join( "~n" )
+		Local tree:=_js.Flush()
 		
 		stringio.SaveString( tree,_pagesDir+"index.js" )
 
@@ -31,15 +80,21 @@ Class HtmlDocsMaker Extends DocsMaker
 	
 		Local nmspaces:=New StringMap<NamespaceScope>
 		
+		Local nmspaceDocs:=New StringMap<String>
+		
 		For Local fscope:=Eachin _module.fileScopes
 		
 			Local nmspace:=Cast<NamespaceScope>( fscope.outer )
 			If Not nmspace Continue
 			
-			nmspaces[nmspace.ntype.ident]=nmspace
+			nmspaces[nmspace.Name]=nmspace
+			
+			nmspaceDocs[nmspace.Name]+=fscope.fdecl.docs
 		Next
 
 		Local page:=""
+		
+		#rem
 		Local md:=stringio.LoadString( _module.baseDir+"/docs/module.md" )
 		If md
 			_scope=Null
@@ -48,12 +103,13 @@ Class HtmlDocsMaker Extends DocsMaker
 			Local html:=Flush()
 			SavePage( html,page )
 		Endif
+		#end
 		
 		BeginNode( _module.name,page )
 		
 		For Local nmspace:=Eachin nmspaces.Values
 		
-			EmitNamespace( nmspace )
+			EmitNamespace( nmspace,nmspaceDocs[nmspace.Name] )
 			
 		Next
 		
@@ -62,55 +118,28 @@ Class HtmlDocsMaker Extends DocsMaker
 	
 	Private
 	
-	Field _buf:=New StringStack
-	Field _indent:String
-	Field _sep:Bool
-	
-	Field _posStack:=New IntStack
-	
-	Method EmitTree( str:String )
-	
-		If str.StartsWith( "}" ) Or str.StartsWith( "]" )
-		
-			_indent=_indent.Slice( 0,-2 )
-			_sep=False
-			
-		Endif
-	
-		If _sep str=","+str
-		_sep=True
-		
-		_buf.Push( _indent+str )
-	
-		If str.EndsWith( "{" ) Or str.EndsWith( "[" ) 
-			_indent+="  "
-			_sep=False
-		Endif
-	
-	End
+	Field _js:=New JsonBuffer
+
+	Field _namespaceDocs:=New StringMap<String>
 	
 	Method BeginNode( name:String,page:String="" )
 	
-		If page page=",page:'"+_module.name+":"+page+"'"
-		_posStack.Push( _sep )
-		_posStack.Push( _buf.Length )
-		EmitTree( "{ name:'"+name+"'"+page+",children:[" )
+		If page page=",data:{page:'"+_module.name+":"+page+"'}"
+		
+		_js.Emit( "{ text:'"+name+"'"+page+",children:[" )
 
 	End
 	
-	Method EndNode( force:Bool=False )
-		EmitTree( "] }" )
-		Local pos:=_posStack.Pop()
-		Local sep:=_posStack.Pop()
-		If force Or _buf.Length-pos>2 Return
-		_buf.Resize( pos )
-		_sep=sep
+	Method EndNode()
+
+		_js.Emit( "] }" )
 	End
 	
 	Method EmitLeaf( name:String,page:String="" )
 	
-		If page page=",page:'"+_module.name+":"+page+"'"
-		EmitTree( "{ name:'"+name+"'"+page+",children:[] }" )
+		If page page=",data:{page:'"+_module.name+":"+page+"'}"
+		
+		_js.Emit( "{ text:'"+name+"'"+page+",children:[] }" )
 		
 	End
 	
@@ -120,13 +149,13 @@ Class HtmlDocsMaker Extends DocsMaker
 
 	End
 	
-	Method EmitNode( decl:Decl,scope:Scope,page:String="",force:Bool=False )
+	Method EmitNode( decl:Decl,scope:Scope,page:String="" )
 	
-		EmitNode( decl.ident,scope,page,force )
+		EmitNode( decl.ident,scope,page )
 
 	End
 	
-	Method EmitNode( name:String,scope:Scope,page:String="",force:Bool=False )
+	Method EmitNode( name:String,scope:Scope,page:String="" )
 	
 		BeginNode( name,page )
 	
@@ -182,28 +211,31 @@ Class HtmlDocsMaker Extends DocsMaker
 		EmitFuncs( scope,"function" )
 		EndNode()
 		
-		EndNode( force )
+		EndNode()
 		
 	End
 	
-	Method EmitNamespaces( scope:Scope )
+	Method EmitNamespace( nmspace:NamespaceScope,docs:String )
+
+		_linkScope=nmspace
 	
-		For Local node:=Eachin scope.nodes
+		_md.Emit( "_Module: &lt;"+_module.name+"&gt;_  " )
+		_md.Emit( "_Namespace: "+nmspace.Name+"_" )
 		
-			Local ntype:=Cast<NamespaceType>( node.Value )
-			If Not ntype Continue
-			
-			EmitNode( ntype.Name,ntype.scope )
-			
-		Next
-	End
-	
-	Method EmitNamespace( nmspace:NamespaceScope )
+		EmitMembers( "alias",nmspace,True )
+		EmitMembers( "enum",nmspace,True )
+		EmitMembers( "struct",nmspace,True )
+		EmitMembers( "class",nmspace,True )
+		EmitMembers( "interface",nmspace,True )
+		EmitMembers( "const",nmspace,True )
+		EmitMembers( "global",nmspace,True )
+		EmitMembers( "function",nmspace,True )
+		
+		_md.Emit( docs )
 
-		Local docs:=MakeNamespaceDocs( nmspace )
-		If Not docs Return
+		docs=_md.Flush()
 		
-		Local page:=NamespacePage( nmspace )
+		Local page:=NamespacePath( nmspace )
 		SavePage( docs,page )
 		
 		EmitNode( nmspace.ntype.Name,nmspace,page )
@@ -214,14 +246,17 @@ Class HtmlDocsMaker Extends DocsMaker
 		For Local node:=Eachin scope.nodes
 	
 			Local vvar:=Cast<VarValue>( node.Value )
-			If Not vvar Or vvar.transFile.module<>_module Or vvar.vdecl.kind<>kind Continue
+			If Not vvar Or vvar.vdecl.kind<>kind Or DocsHidden( vvar.vdecl ) Continue
 			
-			Local docs:=MakeVarDocs( vvar )
-			If Not docs Continue
+			If vvar.transFile.module<>_module Continue
 			
-			Local page:=DeclPage( vvar.vdecl,vvar.scope )
+			Local docs:=MakeVarDocs( vvar )
+
+			Local page:=DeclPath( vvar.vdecl,vvar.scope )
 			SavePage( docs,page )
 			
+			Print "save page:"+page
+			
 			EmitLeaf( vvar.vdecl,page )
 			
 		Next
@@ -233,12 +268,11 @@ Class HtmlDocsMaker Extends DocsMaker
 		For Local node:=Eachin scope.nodes
 		
 			Local atype:=Cast<AliasType>( node.Value )
-			If Not atype Or atype.adecl.kind<>kind Continue
-			
+			If Not atype Or atype.adecl.kind<>kind Or DocsHidden( atype.adecl ) Continue
+
 			Local docs:=MakeAliasDocs( atype )
-			If Not docs Continue
-			
-			Local page:=DeclPage( atype.adecl,atype.scope )
+
+			Local page:=DeclPath( atype.adecl,atype.scope )
 			SavePage( docs,page )
 			
 			EmitLeaf( atype.adecl,page )
@@ -252,12 +286,11 @@ Class HtmlDocsMaker Extends DocsMaker
 		For Local node:=Eachin scope.nodes
 	
 			Local etype:=Cast<EnumType>( node.Value )
-			If Not etype Or etype.edecl.kind<>kind Continue
+			If Not etype Or etype.edecl.kind<>kind Or DocsHidden( etype.edecl ) Continue
 			
 			Local docs:=MakeEnumDocs( etype )
-			If Not docs Continue
-			
-			Local page:=DeclPage( etype.edecl,etype.scope.outer )
+
+			Local page:=DeclPath( etype.edecl,etype.scope.outer )
 			SavePage( docs,page )
 			
 			EmitLeaf( etype.edecl,page )
@@ -271,15 +304,16 @@ Class HtmlDocsMaker Extends DocsMaker
 		For Local node:=Eachin scope.nodes
 	
 			Local ctype:=Cast<ClassType>( node.Value )
-			If Not ctype Or ctype.transFile.module<>_module Or ctype.cdecl.kind<>kind Continue
+			If Not ctype Or ctype.cdecl.kind<>kind Or DocsHidden( ctype.cdecl ) Continue
+			
+			If ctype.transFile.module<>_module Continue
 			
 			Local docs:=MakeClassDocs( ctype )
-			If Not docs Continue
 
-			Local page:=DeclPage( ctype.cdecl,ctype.scope.outer )
+			Local page:=DeclPath( ctype.cdecl,ctype.scope.outer )
 			SavePage( docs,page )
 			
-			EmitNode( ctype.cdecl,ctype.scope,page,True )
+			EmitNode( ctype.cdecl,ctype.scope,page )
 		Next
 	
 	End
@@ -289,12 +323,11 @@ Class HtmlDocsMaker Extends DocsMaker
 		For Local node:=Eachin scope.nodes
 		
 			Local plist:=Cast<PropertyList>( node.Value )
-			If Not plist Or plist.pdecl.kind<>kind Continue
+			If Not plist Or plist.pdecl.kind<>kind Or DocsHidden( plist.pdecl ) Continue
 			
 			Local docs:=MakePropertyDocs( plist )
-			If Not docs Continue
 			
-			Local page:=DeclPage( plist.pdecl,plist.scope )
+			Local page:=DeclPath( plist.pdecl,plist.scope )
 			SavePage( docs,page )
 			
 			EmitLeaf( plist.pdecl,page )
@@ -313,7 +346,7 @@ Class HtmlDocsMaker Extends DocsMaker
 			Local docs:=MakeFuncDocs( flist,kind )
 			If Not docs Continue
 			
-			Local page:=DeclPage( flist.funcs[0].fdecl,flist.funcs[0].scope )
+			Local page:=DeclPath( flist.funcs[0].fdecl,flist.funcs[0].scope )
 			SavePage( docs,page )
 			
 			EmitLeaf( flist.funcs[0].fdecl,page )

+ 1 - 1
src/mx2new/mx2.monkey2

@@ -48,4 +48,4 @@ Using lib.c
 ' 3) edit .sh and .bat files to use new version (common.sh, updatemx2cc.bat, rebuildmx2cc.bat)
 ' 4) ./rebuildall
 '
-Const MX2CC_VERSION:="009"
+Const MX2CC_VERSION:="010"

+ 18 - 24
src/mx2new/mx2cc.monkey2

@@ -8,6 +8,7 @@ Using mx2.docs
 
 #Import "mx2.monkey2"
 
+#Import "makedocs.monkey2"
 #Import "docsmaker.monkey2"
 #Import "htmldocsmaker.monkey2"
 
@@ -23,6 +24,8 @@ Const TestArgs:="mx2cc makedocs std"
 
 'Const TestArgs:="mx2cc makeapp src/mx2new/test.monkey2"
 
+'Const TestArgs:="mx2cc makeapp src/ted2/ted2.monkey2"
+
 'Const TestArgs:="mx2cc makemods -clean -config=release monkey libc miniz stb-image hoedown std"
 
 'Const TestArgs:="mx2cc makeapp -verbose -target=desktop -config=release src/mx2new/mx2cc.monkey2"
@@ -87,11 +90,12 @@ Function MakeApp( args:String[] )
 
 	Local opts:=New BuildOpts
 	opts.productType="app"
+	opts.appType="console"
 	opts.target="desktop"
 	opts.config="debug"
 	opts.clean=False
 	opts.fast=True
-	opts.run=True
+	opts.run=true
 	opts.verbose=0
 	
 	args=ParseOpts( opts,args )
@@ -217,10 +221,12 @@ Function MakeDocs( args:String[] )
 
 	Next
 	
+'	stringio.SaveString( "mx2_api_tree="+mx2_api+";","docs/api-tree.js" )
+	
 	Local index:=stringio.LoadString( "docs/modules_template.html" )
 	index=index.Replace( "${MX2_API}",mx2_api )
 	stringio.SaveString( index,"docs/modules.html" )
-
+	
 End
 
 Function ParseOpts:String[]( opts:BuildOpts,args:String[] )
@@ -251,26 +257,33 @@ Function ParseOpts:String[]( opts:BuildOpts,args:String[] )
 		Local opt:=arg.Slice( 0,j ),val:=arg.Slice( j+1 ).ToLower()
 		
 		Select opt
+		Case "-apptype"
+			Select val
+			Case "gui","console"
+				opts.appType=val
+			Default
+				Fail( "Invalid value for 'apptype' option: '"+val+"' - must be 'gui' or 'console'" )
+			End
 		Case "-target"
 			Select val
 			Case "desktop","emscripten"
 				opts.target=val
 			Default
-				Fail( "Invalid value for 'target' option: '"+val+"'" )
+				Fail( "Invalid value for 'target' option: '"+val+"' - must be 'desktop' or 'emscripten'" )
 			End
 		Case "-config"
 			Select val
 			Case "debug","release"
 				opts.config=val
 			Default
-				Fail( "Invalid value for 'config' option: '"+val+"'" )
+				Fail( "Invalid value for 'config' option: '"+val+"' - must be 'debug' or 'release'" )
 			End
 		Case "-verbose"
 			Select val
 			Case "0","1","2","-1"
 				opts.verbose=Int( val )
 			Default
-				Fail( "Invalid value for 'verbose' option: '"+val+"'" )
+				Fail( "Invalid value for 'verbose' option: '"+val+"' - must be '0', '1', '2' or '-1'" )
 			End
 		Default
 			Fail( "Invalid option: '"+opt+"'" )
@@ -333,25 +346,6 @@ Function EnumModules:String[]()
 	Return out.ToArray()
 End
 
-#rem
-Function EnumModules:String[]()
-
-	Local mods:=New StringStack
-	
-	For Local line:=Eachin stringio.LoadString( "modules/modules.txt" ).Split( "~n" )
-	
-		Local i:=line.Find( "'" )
-		If i<>-1 line=line.Slice( 0,i )
-		
-		line=line.Trim()
-		If line mods.Push( line )
-		
-	Next
-	
-	Return mods.ToArray()
-End
-#end
-
 Function LoadEnv:Bool( path:String )
 
 	SetEnv( "MX2_HOME",CurrentDir() )

+ 1 - 0
src/mx2new/parser.monkey2

@@ -122,6 +122,7 @@ Class Parser
 					If Not fileScope Or decls.Length Or _usings.Length Error( "'Namespace' must appear at the start of the file" )
 					If _fdecl.nmspace Error( "Duplicate namespace declaration" )
 					Bump()					
+					_fdecl.docs=Docs()
 					_fdecl.nmspace=ParseNamespaceIdent()
 					ParseEol()
 				Case "using"