diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala | 71 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/html/Page.scala | 93 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/html/page/Index.scala | 70 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala | 68 | ||||
-rw-r--r-- | test/scaladoc/scala/IndexScriptTest.scala | 52 | ||||
-rw-r--r-- | test/scaladoc/scala/IndexTest.scala | 20 |
7 files changed, 217 insertions, 158 deletions
diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala index 8fc044c195..88cd589797 100644 --- a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala @@ -97,6 +97,7 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) { copyResource("lib/unselected.png") new page.Index(universe, index) writeFor this + new page.IndexScript(universe, index) writeFor this writeTemplates(page => page.writeFor(this)) diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala index d99403e5ba..cfa846b097 100644 --- a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala +++ b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala @@ -15,18 +15,11 @@ import xml.dtd.{DocType, PublicID} import scala.collection._ import scala.reflect.NameTransformer import java.nio.channels.Channels -import java.io.{FileOutputStream, File} /** An html page that is part of a Scaladoc site. * @author David Bernard * @author Gilles Dubochet */ -abstract class HtmlPage { thisPage => - - /** The path of this page, relative to the API site. `path.tail` is a list of folder names leading to this page (from - * closest package to one-above-root package), `path.head` is the file name of this page. Note that `path` has a - * length of at least one. */ - def path: List[String] - +abstract class HtmlPage extends Page { thisPage => /** The title of this page. */ protected def title: String @@ -36,9 +29,6 @@ abstract class HtmlPage { thisPage => /** The body of this page. */ def body: NodeSeq - /** Writes this page as a file. The file's location is relative to the generator's site root, and the encoding is - * also defined by the generator. - * @param generator The generator that is writing this page. */ def writeFor(site: HtmlFactory): Unit = { val doctype = DocType("html", PublicID("-//W3C//DTD XHTML 1.1//EN", "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"), Nil) @@ -51,10 +41,7 @@ abstract class HtmlPage { thisPage => </head> { body } </html> - val pageFile = new File(site.siteRoot, absoluteLinkTo(thisPage.path)) - val pageFolder = pageFile.getParentFile - if (!pageFolder.exists) pageFolder.mkdirs() - val fos = new FileOutputStream(pageFile.getPath) + val fos = createFileOutputStream(site) val w = Channels.newWriter(fos.getChannel, site.encoding) try { w.write("<?xml version='1.0' encoding='" + site.encoding + "'?>\n") @@ -68,52 +55,6 @@ abstract class HtmlPage { thisPage => //XML.save(pageFile.getPath, html, site.encoding, xmlDecl = false, doctype = doctype) } - def templateToPath(tpl: TemplateEntity): List[String] = { - def doName(tpl: TemplateEntity): String = - NameTransformer.encode(tpl.name) + (if (tpl.isObject) "$" else "") - def downPacks(pack: Package): List[String] = - if (pack.isRootPackage) Nil else (doName(pack) :: downPacks(pack.inTemplate)) - def downInner(nme: String, tpl: TemplateEntity): (String, Package) = { - tpl.inTemplate match { - case inPkg: Package => (nme + ".html", inPkg) - case inTpl => downInner(doName(inTpl) + "$" + nme, inTpl) - } - } - val (file, pack) = - tpl match { - case p: Package => ("package.html", p) - case _ => downInner(doName(tpl), tpl) - } - file :: downPacks(pack) - } - - /** A relative link from this page to some destination class entity. - * @param destEntity The class or object entity that the link will point to. */ - def relativeLinkTo(destClass: TemplateEntity): String = - relativeLinkTo(templateToPath(destClass)) - - /** A relative link from this page to some destination page in the Scaladoc site. - * @param destPage The page that the link will point to. */ - def relativeLinkTo(destPage: HtmlPage): String = { - relativeLinkTo(destPage.path) - } - - /** A relative link from this page to some destination path. - * @param destPath The path that the link will point to. */ - def relativeLinkTo(destPath: List[String]): String = { - def relativize(from: List[String], to: List[String]): List[String] = (from, to) match { - case (f :: fs, t :: ts) if (f == t) => // both paths are identical to that point - relativize(fs, ts) - case (fss, tss) => - List.fill(fss.length - 1)("..") ::: tss - } - relativize(thisPage.path.reverse, destPath.reverse).mkString("/") - } - - def absoluteLinkTo(destPath: List[String]): String = { - destPath.reverse.mkString("/") - } - /** Transforms an optional comment into an styled HTML tree representing its body if it is defined, or into an empty * node sequence if it is not. */ def commentToHtml(comment: Option[Comment]): NodeSeq = @@ -229,14 +170,6 @@ abstract class HtmlPage { thisPage => case tpl :: tpls => templateToHtml(tpl) ++ sep ++ templatesToHtml(tpls, sep) } - def docEntityKindToString(ety: DocTemplateEntity) = - if (ety.isTrait) "trait" - else if (ety.isCaseClass) "case class" - else if (ety.isClass) "class" - else if (ety.isObject) "object" - else if (ety.isPackage) "package" - else "class" // FIXME: an entity *should* fall into one of the above categories, but AnyRef is somehow not - /** Returns the _big image name corresponding to the DocTemplate Entity (upper left icon) */ def docEntityKindToBigImage(ety: DocTemplateEntity) = if (ety.isTrait && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None) "trait_to_object_big.png" diff --git a/src/compiler/scala/tools/nsc/doc/html/Page.scala b/src/compiler/scala/tools/nsc/doc/html/Page.scala new file mode 100644 index 0000000000..f72b0a49eb --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/html/Page.scala @@ -0,0 +1,93 @@ +package scala.tools.nsc.doc.html +import scala.tools.nsc.doc.model._ +import java.io.{FileOutputStream, File} +import scala.reflect.NameTransformer + +abstract class Page { + thisPage => + + /** The path of this page, relative to the API site. `path.tail` is a list of folder names leading to this page (from + * closest package to one-above-root package), `path.head` is the file name of this page. Note that `path` has a + * length of at least one. */ + def path: List[String] + + def absoluteLinkTo(path: List[String]) = path.reverse.mkString("/") + + def createFileOutputStream(site: HtmlFactory) = { + val file = new File(site.siteRoot, absoluteLinkTo(thisPage.path)) + val folder = file.getParentFile + if (! folder.exists) { + folder.mkdirs + } + new FileOutputStream(file.getPath) + } + + /** Writes this page as a file. The file's location is relative to the generator's site root, and the encoding is + * also defined by the generator. + * @param generator The generator that is writing this page. */ + def writeFor(site: HtmlFactory): Unit + + def docEntityKindToString(ety: DocTemplateEntity) = + if (ety.isTrait) "trait" + else if (ety.isCaseClass) "case class" + else if (ety.isClass) "class" + else if (ety.isObject) "object" + else if (ety.isPackage) "package" + else "class" // FIXME: an entity *should* fall into one of the above categories, but AnyRef is somehow not + + def templateToPath(tpl: TemplateEntity): List[String] = { + def doName(tpl: TemplateEntity): String = + NameTransformer.encode(tpl.name) + (if (tpl.isObject) "$" else "") + def downPacks(pack: Package): List[String] = + if (pack.isRootPackage) Nil else (doName(pack) :: downPacks(pack.inTemplate)) + def downInner(nme: String, tpl: TemplateEntity): (String, Package) = { + tpl.inTemplate match { + case inPkg: Package => (nme + ".html", inPkg) + case inTpl => downInner(doName(inTpl) + "$" + nme, inTpl) + } + } + val (file, pack) = + tpl match { + case p: Package => ("package.html", p) + case _ => downInner(doName(tpl), tpl) + } + file :: downPacks(pack) + } + + /** A relative link from this page to some destination class entity. + * @param destEntity The class or object entity that the link will point to. */ + def relativeLinkTo(destClass: TemplateEntity): String = + relativeLinkTo(templateToPath(destClass)) + + /** A relative link from this page to some destination page in the Scaladoc site. + * @param destPage The page that the link will point to. */ + def relativeLinkTo(destPage: HtmlPage): String = { + relativeLinkTo(destPage.path) + } + + /** A relative link from this page to some destination path. + * @param destPath The path that the link will point to. */ + def relativeLinkTo(destPath: List[String]): String = { + def relativize(from: List[String], to: List[String]): List[String] = (from, to) match { + case (f :: fs, t :: ts) if (f == t) => // both paths are identical to that point + relativize(fs, ts) + case (fss, tss) => + List.fill(fss.length - 1)("..") ::: tss + } + relativize(thisPage.path.reverse, destPath.reverse).mkString("/") + } + + def isExcluded(dtpl: DocTemplateEntity) = { + val qname = dtpl.qualifiedName + ( ( qname.startsWith("scala.Tuple") || qname.startsWith("scala.Product") || + qname.startsWith("scala.Function") || qname.startsWith("scala.runtime.AbstractFunction") + ) && !( + qname == "scala.Tuple1" || qname == "scala.Tuple2" || + qname == "scala.Product" || qname == "scala.Product1" || qname == "scala.Product2" || + qname == "scala.Function" || qname == "scala.Function1" || qname == "scala.Function2" || + qname == "scala.runtime.AbstractFunction0" || qname == "scala.runtime.AbstractFunction1" || + qname == "scala.runtime.AbstractFunction2" + ) + ) + } +} diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala index 4fc10b2ec2..7203230084 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala @@ -48,23 +48,7 @@ class Index(universe: doc.Universe, index: doc.Index) extends HtmlPage { </div> </body> - - def isExcluded(dtpl: DocTemplateEntity) = { - val qname = dtpl.qualifiedName - ( ( qname.startsWith("scala.Tuple") || qname.startsWith("scala.Product") || - qname.startsWith("scala.Function") || qname.startsWith("scala.runtime.AbstractFunction") - ) && !( - qname == "scala.Tuple1" || qname == "scala.Tuple2" || - qname == "scala.Product" || qname == "scala.Product1" || qname == "scala.Product2" || - qname == "scala.Function" || qname == "scala.Function1" || qname == "scala.Function2" || - qname == "scala.runtime.AbstractFunction0" || qname == "scala.runtime.AbstractFunction1" || - qname == "scala.runtime.AbstractFunction2" - ) - ) - } - def browser = - <xml:group> <div id="browser" class="ui-layout-west"> <div class="ui-west-center"> <div id="filter"></div> @@ -121,60 +105,8 @@ class Index(universe: doc.Universe, index: doc.Index) extends HtmlPage { </xml:group> } packageElem(universe.rootPackage) - }</div></div>{ scriptElement } + }</div></div><script src="index.js"></script> </div> - </xml:group> - - def mergeByQualifiedName(source: List[DocTemplateEntity]): Map[String, List[DocTemplateEntity]]= { - var result = Map[String, List[DocTemplateEntity]]() - - for (t <- source) { - val k = t.qualifiedName - result += k -> (result.getOrElse(k, List()) :+ t) - } - - result - } - - def scriptElement = { - val packages = allPackagesWithTemplates.toIterable.map(_ match { - case (pack, templates) => { - val merged = mergeByQualifiedName(templates) - - val ary = merged.keys.toList.sortBy(_.toLowerCase).map(key => { - val pairs = merged(key).map( - t => docEntityKindToString(t) -> relativeLinkTo(t) - ) :+ ("name" -> key) - - JSONObject(scala.collection.immutable.Map(pairs : _*)) - }) - - pack.qualifiedName -> JSONArray(ary) - } - }).toSeq - - val obj = - JSONObject(scala.collection.immutable.Map(packages : _*)).toString() - - <script type="text/javascript"> - Index.PACKAGES = {scala.xml.Unparsed(obj)}; - </script> - } - - def allPackagesWithTemplates: Map[Package, List[DocTemplateEntity]] = { - Map(allPackages.map((key) => { - key -> key.templates.filter(t => !t.isPackage && !isExcluded(t)) - }) : _*) - } - - def allPackages: List[Package] = { - def f(parent: Package): List[Package] = { - parent.packages.flatMap( - p => f(p) :+ p - ) - } - f(universe.rootPackage).sortBy(_.toString) - } def packageQualifiedName(ety: DocTemplateEntity): String = if (ety.inTemplate.isPackage) ety.name else (packageQualifiedName(ety.inTemplate) + "." + ety.name) diff --git a/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala b/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala new file mode 100644 index 0000000000..2cafe6caa3 --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala @@ -0,0 +1,68 @@ +package scala.tools.nsc.doc.html.page +import scala.tools.nsc.doc +import scala.tools.nsc.doc.model.{Package, DocTemplateEntity} +import scala.tools.nsc.doc.html.{Page, HtmlFactory} +import java.nio.channels.Channels +import scala.util.parsing.json.{JSONObject, JSONArray} + +class IndexScript(universe: doc.Universe, index: doc.Index) extends Page { + def path = List("index.js") + + override def writeFor(site: HtmlFactory): Unit = { + val stream = createFileOutputStream(site) + val writer = Channels.newWriter(stream.getChannel, site.encoding) + try { + writer.write("Index.PACKAGES = " + packages.toString() + ";") + } + finally { + writer.close + stream.close + } + } + + val packages = { + val pairs = allPackagesWithTemplates.toIterable.map(_ match { + case (pack, templates) => { + val merged = mergeByQualifiedName(templates) + + val ary = merged.keys.toList.sortBy(_.toLowerCase).map(key => { + val pairs = merged(key).map( + t => docEntityKindToString(t) -> relativeLinkTo(t) + ) :+ ("name" -> key) + + JSONObject(scala.collection.immutable.Map(pairs : _*)) + }) + + pack.qualifiedName -> JSONArray(ary) + } + }).toSeq + + JSONObject(scala.collection.immutable.Map(pairs : _*)) + } + + def mergeByQualifiedName(source: List[DocTemplateEntity]) = { + var result = Map[String, List[DocTemplateEntity]]() + + for (t <- source) { + val k = t.qualifiedName + result += k -> (result.getOrElse(k, List()) :+ t) + } + + result + } + + def allPackages = { + def f(parent: Package): List[Package] = { + parent.packages.flatMap( + p => f(p) :+ p + ) + } + f(universe.rootPackage).sortBy(_.toString) + } + + def allPackagesWithTemplates = { + Map(allPackages.map((key) => { + key -> key.templates.filter(t => !t.isPackage && !isExcluded(t)) + }) : _*) + } +} diff --git a/test/scaladoc/scala/IndexScriptTest.scala b/test/scaladoc/scala/IndexScriptTest.scala new file mode 100644 index 0000000000..991491c376 --- /dev/null +++ b/test/scaladoc/scala/IndexScriptTest.scala @@ -0,0 +1,52 @@ +import org.scalacheck._ +import org.scalacheck.Prop._ + +import scala.tools.nsc.doc +import scala.tools.nsc.doc.html.page.IndexScript +import java.net.URLClassLoader + +object Test extends Properties("IndexScript") { + + def getClasspath = { + val loader = Thread.currentThread.getContextClassLoader + val paths = loader.asInstanceOf[URLClassLoader].getURLs + val morepaths = loader.getParent.asInstanceOf[URLClassLoader].getURLs + (paths ++ morepaths).map(_.getPath).mkString(java.io.File.pathSeparator) + } + + val docFactory = { + val settings = new doc.Settings({Console.err.println(_)}) + settings.classpath.value = getClasspath + val reporter = new scala.tools.nsc.reporters.ConsoleReporter(settings) + new doc.DocFactory(reporter, settings) + } + + val indexModelFactory = doc.model.IndexModelFactory + + def createIndexScript(path: String) = + docFactory.makeUniverse(List(path)) match { + case Some(universe) => { + val index = new IndexScript(universe, + indexModelFactory.makeIndex(universe)) + Some(index) + } + case _ => + None + } + + property("allPackages") = { + createIndexScript("src/compiler/scala/tools/nsc/doc/html/page/Index.scala") match { + case Some(index) => + index.allPackages.map(_.toString) == List( + "scala", + "scala.tools", + "scala.tools.nsc", + "scala.tools.nsc.doc", + "scala.tools.nsc.doc.html", + "scala.tools.nsc.doc.html.page" + ) + case None => + false + } + } +} diff --git a/test/scaladoc/scala/IndexTest.scala b/test/scaladoc/scala/IndexTest.scala index 5e3d02e045..7679bab0c6 100644 --- a/test/scaladoc/scala/IndexTest.scala +++ b/test/scaladoc/scala/IndexTest.scala @@ -79,24 +79,4 @@ object Test extends Properties("Index") { case None => false } } - - property("allPackages") = { - createIndex("src/compiler/scala/tools/nsc/doc/html/page/Index.scala") match { - - case Some(index) => - index.allPackages.map(_.toString) == List( - "scala", - "scala.tools", - "scala.tools.nsc", - "scala.tools.nsc.doc", - "scala.tools.nsc.doc.html", - "scala.tools.nsc.doc.html.page" - ) - - case None => - false - - } - } - } |