diff options
author | chrisJames <chrisJames@epfl.ch> | 2010-08-04 12:32:01 +0000 |
---|---|---|
committer | chrisJames <chrisJames@epfl.ch> | 2010-08-04 12:32:01 +0000 |
commit | bf44cd12b16c701cc4ac94c86357128d44afc147 (patch) | |
tree | a18a2dcb863060f0dc0436f64079131b2cb2a319 | |
parent | db99926628a2b636a548049c1204fee78c77b9bb (diff) | |
download | scala-bf44cd12b16c701cc4ac94c86357128d44afc147.tar.gz scala-bf44cd12b16c701cc4ac94c86357128d44afc147.tar.bz2 scala-bf44cd12b16c701cc4ac94c86357128d44afc147.zip |
[Scaladoc]
Prints default Values, considers anyRef as a class. closes #3105. Review
by prokopec.
7 files changed, 187 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala index 066f800f79..d303d1e65a 100644 --- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala @@ -26,7 +26,7 @@ import reporters.Reporter class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor => /** The unique compiler instance used by this processor and constructed from its `settings`. */ - object compiler extends Global(settings, reporter) { + object compiler extends Global(settings, reporter) with interactive.RangePositions{ override protected def computeInternalPhases() { phasesSet += syntaxAnalyzer phasesSet += analyzer.namerFactory @@ -51,7 +51,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor compiler.addSourceless assert(settings.docformat.value == "html") if (!reporter.hasErrors) { - val modelFactory = (new model.ModelFactory(compiler, settings) with model.comment.CommentFactory) + val modelFactory = (new model.ModelFactory(compiler, settings) with model.comment.CommentFactory with model.TreeFactory) val docModel = modelFactory.makeModel println("model contains " + modelFactory.templatesCount + " documentable templates") (new html.HtmlFactory(docModel)).generate diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala index dd7633a9a8..324b04a54f 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -39,8 +39,11 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { case _ => Nil }) sortBy (_.name) + /* for body, there is a special case for AnyRef, otherwise AnyRef appears like a package/object + * this problem should be fixed, this implementation is just a patch + */ val body = - <body class={ if (tpl.isTrait || tpl.isClass) "type" else "value" } onload="windowTitle();"> + <body class={ if (tpl.isTrait || tpl.isClass || tpl.qualifiedName == "scala.AnyRef") "type" else "value" } onload="windowTitle();"> { if (tpl.isRootPackage || tpl.inTemplate.isRootPackage) NodeSeq.Empty @@ -406,7 +409,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { // notice the }{ in the next lines, they are necessary to avoid a undesired withspace in output <span name={ vl.name }>{ Text(vl.name + ": ") }{ typeToHtml(vl.resultType, hasLinks) }{ if(!vl.defaultValue.isEmpty) { - Text(" = ") ++ <span class="default">{vl.defaultValue.get}</span> + defaultValueToHtml(vl.defaultValue.get); } else NodeSeq.Empty }</span> @@ -460,4 +463,71 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { } } + /** */ + def defaultValueToHtml(defVal:TreeEntity):NodeSeq = { + var index = 0 + val str = defVal.expression + val length = str.length + var myXml: NodeSeq = NodeSeq.Empty + for( x <- defVal.refs) { + val from = x._1 + val to = x._2._2 + if (index < from) { + myXml ++= stringToXml(str.substring(index,from)) + index = from + } + + if (index == from) { + val member:Entity = x._2._1 + member match { + case mbr: DocTemplateEntity => + val link = relativeLinkTo(mbr) + myXml ++= <span class="name"><a href={link}>{str.substring(from, to)}</a></span> + case mbr: MemberEntity => + val anchor = "#" + mbr.name + defParamsString(mbr) + ":" + mbr.resultType.name + val link = relativeLinkTo(mbr.inTemplate) + myXml ++= <span class="name"><a href={link ++ anchor}>{str.substring(from, to)}</a></span> + case _ => assert(false, "unexpected case in defaultValueToHtml") + } + index = to + } + } + // function used in the MemberEntity case above + def defParamsString(mbr: Entity):String = mbr match { + case d:MemberEntity with Def => defParamsToString(d) + case _ => "" + } + + if (index <= length-1) myXml ++= stringToXml(str.substring(index, length )) + + Text(" =") ++ + { + if(length< 7) <span class="symbol">{ myXml }</span> + else <span class="defval" name={ myXml }>{ " ..." }</span> + } + } + + /** Makes text good looking in the html page : newlines and basic indentation, + * You must change this function if you want to improve pretty printing of default Values + */ + def stringToXml(text: String): NodeSeq = { + var goodLookingXml: NodeSeq = NodeSeq.Empty + var indent = 0 + for(c<-text) c match { + case '{' => indent+=1 + goodLookingXml ++= Text("{") + case '}' => indent-=1 + goodLookingXml ++= Text("}") + case '\n' => + goodLookingXml++= <br/> ++ indentation + case _ => goodLookingXml ++= Text(c.toString) + } + def indentation:NodeSeq = { + var indentXml = NodeSeq.Empty + for (x<- 1 to indent) indentXml ++= Text(" ") + indentXml + } + goodLookingXml + } + } diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js index 6aacfb1390..c327e0f13e 100644 --- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js @@ -102,6 +102,13 @@ $(document).ready(function(){ $(this.getTip()).text(this.getTrigger().attr("name")); } }); + $(".defval").tooltip({ + tip: "#tooltip", + position:"top center", + onBeforeShow: function(ev) { + $(this.getTip()).html(this.getTrigger().attr("name")) + } + }); var docAllSigs = $("#template .signature"); function commentShowFct(fullComment){ var vis = $(":visible", fullComment); diff --git a/src/compiler/scala/tools/nsc/doc/model/Entity.scala b/src/compiler/scala/tools/nsc/doc/model/Entity.scala index fc84ed8f6c..395ff66f33 100644 --- a/src/compiler/scala/tools/nsc/doc/model/Entity.scala +++ b/src/compiler/scala/tools/nsc/doc/model/Entity.scala @@ -170,7 +170,7 @@ trait TypeParam extends ParameterEntity with HigherKinded { /** A value parameter to a constructor or to a method. */ trait ValueParam extends ParameterEntity { def resultType: TypeEntity - def defaultValue: Option[String] + def defaultValue: Option[TreeEntity] def isImplicit: Boolean } diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index fca26e69ce..f430b31c05 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -14,7 +14,7 @@ import symtab.Flags import model.{ RootPackage => RootPackageEntity } /** This trait extracts all required information for documentation from compilation units */ -class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory: ModelFactory with CommentFactory => +class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory: ModelFactory with CommentFactory with TreeFactory => import global._ import definitions.{ ObjectClass, ScalaObjectClass, RootPackage, EmptyPackage, NothingClass, AnyClass, AnyRefClass } @@ -453,7 +453,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory (currentRun.units filter (_.source.file == aSym.sourceFile)).toList match { case List(unit) => (unit.body find (_.symbol == aSym)) match { - case Some(ValDef(_,_,_,rhs)) => Some(rhs.toString) + case Some(ValDef(_,_,_,rhs)) => + Some(makeTree(rhs)) case _ => None } case _ => None diff --git a/src/compiler/scala/tools/nsc/doc/model/TreeEntity.scala b/src/compiler/scala/tools/nsc/doc/model/TreeEntity.scala new file mode 100644 index 0000000000..7a0c8c7961 --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/model/TreeEntity.scala @@ -0,0 +1,16 @@ + + + +/** we create a TreeEntity to store some text and some hyperLinks to make on entities in it */ + +package scala.tools.nsc +package doc +package model + +import scala.collection.immutable.TreeMap + + +class TreeEntity { + var expression:String = "" + var refs = new TreeMap[Int, (Entity, Int)] // start, (Entity to be linked to , end) +}
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/doc/model/TreeFactory.scala b/src/compiler/scala/tools/nsc/doc/model/TreeFactory.scala new file mode 100755 index 0000000000..6d71e93ae4 --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/model/TreeFactory.scala @@ -0,0 +1,86 @@ +package scala.tools.nsc +package doc +package model + +/** The goal of this trait is , using makeDefaultValue, + * to browse the tree of default values to + * 1- have the String of the DefaultValue (tree.expression) + * 2- fill references to create hyperLinks later in html.pageTemplate + * + * It is applied in ModelFactory => makeValueParam + * + */ + +trait TreeFactory { + thisTreeFactory: ModelFactory with TreeFactory => + val global:Global + + import global._ + + def makeTree(rhs:Tree):TreeEntity = { + val printSteps:Boolean = false + val tree = new TreeEntity + val firstIndex = rhs.pos.startOrPoint + + /** Gets the full string of the right hand side of a parameter, without links */ + def makeExpression(rhs:Tree){ + val start = rhs.pos.startOrPoint + val end = rhs.pos.endOrPoint + var expr = "" + for (i <- start until end) expr += rhs.pos.source.content.apply(i) + rhs match { + case Block(r,s) => expr += "}" + case _ => + } + tree.expression += expr + } + + val traverser = new Traverser{ + /** Finds the Entity on which we will later create a link on, + * stores it in tree.refs with its position + */ + def makeLink(rhs:Tree){ + var start = rhs.pos.point - firstIndex + val end = rhs.pos.endOrPoint - firstIndex + if(start != end) { + var asym = rhs.symbol + if (asym.isClass) makeTemplate(asym) match{ + case docTmpl: DocTemplateImpl => + tree.refs += ((start,(docTmpl,end))) + case _ => + } + else if (asym.isTerm && asym.owner.isClass){ + if (asym.isSetter) asym = asym.getter(asym.owner) + makeTemplate(asym.owner) match { + case docTmpl:DocTemplateImpl => + val mbrs:List[MemberImpl] = makeMember(asym,docTmpl) + mbrs foreach {mbr => + tree.refs += ((start,(mbr,end))) + } + case _ => + } + } + } + } + /** Goes through the tree of the rhs and makes links when a Select occurs, + * The cas of New(_) is ignored because the object we want to create a link on + * will be reached with recursivity and we don't want a link on the "new" string + */ + override def traverse(tree:Tree) = tree match { + case Select(qualifier, name) => + qualifier match { + case New(_) => + case _ => makeLink(tree) + } + traverse(qualifier) + case _ => + super.traverse(tree) + } + } + + makeExpression(rhs) + traverser.traverse(rhs) + return tree + } + +} |