Skip to content

Commit

Permalink
[scaladoc] Merges Petr's change to Scaladoc fro...
Browse files Browse the repository at this point in the history
[scaladoc] Merges Petr's change to Scaladoc from the Colladoc branch:
bugfixes, improvements and refactorings that make it possible to extends
Scaladoc into Colladoc.

 - Layout of index uses jQuery UI panel instead of frameset.
 - Search boxes have correct width on Firefox.
 - Scaladoc models the original, untransformed source.
 - Various internal bugfixes & refactorings.
Review by dubochet.
  • Loading branch information
Gilles Dubochet committed Aug 19, 2010
1 parent 1ededc1 commit 16adcd1
Show file tree
Hide file tree
Showing 15 changed files with 689 additions and 183 deletions.
16 changes: 16 additions & 0 deletions docs/licenses/apache_ant.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Scala includes Ant as a library needed for build with sbt

Copyright © 1999-2010, The Apache Software Foundation.
http://ant.apache.org/

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
22 changes: 14 additions & 8 deletions src/compiler/scala/tools/nsc/ast/DocComments.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ trait DocComments { self: SymbolTable =>
/** The raw doc comment map */
val docComments = new HashMap[Symbol, DocComment]

/** Associate comment with symbol `sym` at position `pos`. */
def docComment(sym: Symbol, docStr: String, pos: Position = NoPosition) =
if ((sym ne null) && (sym ne NoSymbol))
docComments += (sym -> DocComment(docStr, pos))

/** The raw doc comment of symbol `sym`, as it appears in the source text, "" if missing.
*/
def rawDocComment(sym: Symbol): String =
Expand All @@ -38,8 +43,9 @@ trait DocComments { self: SymbolTable =>
* If a symbol does not have a doc comment but some overridden version of it does,
* the doc comment of the overridden version is copied instead.
*/
def cookedDocComment(sym: Symbol): String = {
val ownComment = docComments get sym map (_.template) getOrElse ""
def cookedDocComment(sym: Symbol, docStr: String = ""): String = {
val ownComment = if (docStr.isEmpty) docComments get sym map (_.template) getOrElse ""
else DocComment(docStr).template
superComment(sym) match {
case None =>
ownComment
Expand All @@ -57,11 +63,11 @@ trait DocComments { self: SymbolTable =>
* of the same string are done, which is
* interpreted as a recursive variable definition.
*/
def expandedDocComment(sym: Symbol, site: Symbol): String = {
def expandedDocComment(sym: Symbol, site: Symbol, docStr: String = ""): String = {
// when parsing a top level class or module, use the (module-)class itself to look up variable definitions
val site1 = if ((sym.isModule || sym.isClass) && (site hasFlag Flags.PACKAGE)) sym
else site
expandVariables(cookedDocComment(sym), sym, site1)
expandVariables(cookedDocComment(sym, docStr), sym, site1)
}

/** The cooked doc comment of symbol `sym` after variable expansion, or "" if missing.
Expand Down Expand Up @@ -121,8 +127,8 @@ trait DocComments { self: SymbolTable =>
}

/** The cooked doc comment of an overridden symbol */
private def superComment(sym: Symbol): Option[String] =
sym.allOverriddenSymbols.view map cookedDocComment find ("" !=)
protected def superComment(sym: Symbol): Option[String] =
sym.allOverriddenSymbols.view map { cookedDocComment(_) } find ("" !=)

private def mapFind[A, B](xs: Iterable[A])(f: A => Option[B]): Option[B] = {
var res: Option[B] = None
Expand Down Expand Up @@ -230,7 +236,7 @@ trait DocComments { self: SymbolTable =>
* @param site The class for which doc comments are generated
* @return Expanded string
*/
private def expandVariables(str: String, sym: Symbol, site: Symbol): String =
protected def expandVariables(str: String, sym: Symbol, site: Symbol): String =
if (expandCount < expandLimit) {
try {
val out = new StringBuilder
Expand Down Expand Up @@ -422,4 +428,4 @@ trait DocComments { self: SymbolTable =>
}

class ExpansionLimitExceeded(str: String) extends Exception
}
}
13 changes: 9 additions & 4 deletions src/compiler/scala/tools/nsc/doc/DocFactory.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) with interactive.RangePositions{
object compiler extends Global(settings, reporter) with interactive.RangePositions {
override protected def computeInternalPhases() {
phasesSet += syntaxAnalyzer
phasesSet += analyzer.namerFactory
Expand All @@ -46,16 +46,21 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor
/** Creates a scaladoc site for all symbols defined in this call's `files`, as well as those defined in `files` of
* previous calls to the same processor.
* @param files The list of paths (relative to the compiler's source path, or absolute) of files to document. */
def document(files: List[String]): Unit = {
def universe(files: List[String]): Option[Universe] = {
(new compiler.Run()) compile files
compiler.addSourceless
assert(settings.docformat.value == "html")
if (!reporter.hasErrors) {
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
Some(modelFactory.makeModel)
}
else None
}

/** Generate document(s) for all `files` containing scaladoc documenataion.
* @param files The list of paths (relative to the compiler's source path, or absolute) of files to document. */
def document(files: List[String]): Unit =
universe(files) foreach { docModel => (new html.HtmlFactory(docModel)).generate }

}
3 changes: 2 additions & 1 deletion src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ class HtmlFactory(val universe: Universe) {
finally out.close()
}

copyResource("index.html")
copyResource("lib/jquery.js")
copyResource("lib/jquery-ui.js")
copyResource("lib/jquery.layout.js")
copyResource("lib/tools.tooltip.js")
copyResource("lib/scheduler.js")
copyResource("lib/index.css")
Expand Down
157 changes: 82 additions & 75 deletions src/compiler/scala/tools/nsc/doc/html/page/Index.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,104 +15,111 @@ import scala.xml._

class Index(universe: Universe) extends HtmlPage {

def path = List("allclasses.html")
def path = List("index.html")

def title = {
val s = universe.settings
( if (!s.doctitle.isDefault) s.doctitle.value else "" ) +
( if (!s.docversion.isDefault) (" " + s.docversion.value) else "" )
}

def headers =
val headers =
<xml:group>
<link href={ relativeLinkTo(List("index.css", "lib")) } media="screen" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src={ relativeLinkTo{List("jquery.js", "lib")} }></script>
<script type="text/javascript" src={ relativeLinkTo{List("scheduler.js", "lib")} }></script>
<link href={ relativeLinkTo{List("index.css", "lib")} } media="screen" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src={ relativeLinkTo{List("jquery.js", "lib")} }></script>
<script type="text/javascript" src={ relativeLinkTo{List("jquery-ui.js", "lib")} }></script>
<script type="text/javascript" src={ relativeLinkTo{List("jquery.layout.js", "lib")} }></script>
<script type="text/javascript" src={ relativeLinkTo{List("index.js", "lib")} }></script>
<script type="text/javascript" src={ relativeLinkTo{List("scheduler.js", "lib")} }></script>
</xml:group>

def body =
val body =
<body>
<div id="library">
<img class='class icon' width="13" height="13" src='lib/class.png'/>
<img class='trait icon' width="13" height="13" src='lib/trait.png'/>
<img class='object icon' width="13" height="13" src='lib/object.png'/>
<img class='package icon' width="13" height="13" src='lib/package.png'/>
<img class='class icon' width="13" height="13" src={ relativeLinkTo{List("class.png", "lib")} }/>
<img class='trait icon' width="13" height="13" src={ relativeLinkTo{List("trait.png", "lib")} }/>
<img class='object icon' width="13" height="13" src={ relativeLinkTo{List("object.png", "lib")} }/>
<img class='package icon' width="13" height="13" src={ relativeLinkTo{List("package.png", "lib")} }/>
</div>
{ browser }
<div id="content" class="ui-layout-center">
<iframe name="template" src={ relativeLinkTo{List("package.html")} }/>
</div>
<div id="browser">
<div id="filter"></div>
<div class="pack" id="tpl">{
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"
)
</body>

def browser =
<div id="browser" class="ui-layout-west">
<div id="filter"></div>
<div class="pack" id="tpl">{
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 packageElem(pack: model.Package): NodeSeq = {
<xml:group>
{ if (!pack.isRootPackage)
<h3><a class="tplshow" href={ relativeLinkTo(pack) }>{ pack.qualifiedName }</a></h3>
else NodeSeq.Empty
)
}
def packageElem(pack: model.Package): NodeSeq = {
<xml:group>
{ if (!pack.isRootPackage)
<h3><a class="tplshow" href={ relativeLinkTo(pack) }>{ pack.qualifiedName }</a></h3>
else NodeSeq.Empty
}
<ol class="templates">{
val tpls: Map[String, Seq[DocTemplateEntity]] =
(pack.templates filter (t => !t.isPackage && !isExcluded(t) )) groupBy (_.name)

val placeholderSeq: NodeSeq = <div class="placeholder"></div>

def createLink(entity: DocTemplateEntity, includePlaceholder: Boolean, includeText: Boolean) = {
val entityType = docEntityKindToString(entity)
val linkContent = (
{ if (includePlaceholder) placeholderSeq else NodeSeq.Empty }
++
{ if (includeText) <span class="tplLink">{ Text(packageQualifiedName(entity)) }</span> else NodeSeq.Empty }
)
<a class="tplshow" href={ relativeLinkTo(entity) }><span class={ entityType }>({ Text(entityType) })</span>{ linkContent }</a>
}
<ol class="templates">{
val tpls: Map[String, Seq[DocTemplateEntity]] =
(pack.templates filter (t => !t.isPackage && !isExcluded(t) )) groupBy (_.name)

val placeholderSeq: NodeSeq = <div class="placeholder"></div>

def createLink(entity: DocTemplateEntity, includePlaceholder: Boolean, includeText: Boolean) = {
val entityType = docEntityKindToString(entity)
val linkContent = (
{ if (includePlaceholder) placeholderSeq else NodeSeq.Empty }
++
{ if (includeText) <span class="tplLink">{ Text(packageQualifiedName(entity)) }</span> else NodeSeq.Empty }
)
<a class="tplshow" href={ relativeLinkTo(entity) }><span class={ entityType }>({ Text(entityType) })</span>{ linkContent }</a>
}

for (tn <- tpls.keySet.toSeq sortBy (_.toLowerCase)) yield {
val entities = tpls(tn)
val row = (entities find (e => e.isPackage || e.isObject), entities find (e => e.isTrait || e.isClass))

val itemContents = row match {
case (Some(obj), None) => createLink(obj, includePlaceholder = true, includeText = true)
for (tn <- tpls.keySet.toSeq sortBy (_.toLowerCase)) yield {
val entities = tpls(tn)
val row = (entities find (e => e.isPackage || e.isObject), entities find (e => e.isTrait || e.isClass))

case (maybeObj, Some(template)) =>
val firstLink = maybeObj match {
case Some(obj) => createLink(obj, includePlaceholder = false, includeText = false)
case None => placeholderSeq
}
val itemContents = row match {
case (Some(obj), None) => createLink(obj, includePlaceholder = true, includeText = true)

firstLink ++ createLink(template, includePlaceholder = false, includeText = true)
case (maybeObj, Some(template)) =>
val firstLink = maybeObj match {
case Some(obj) => createLink(obj, includePlaceholder = false, includeText = false)
case None => placeholderSeq
}

case _ => // FIXME: this default case should not be necessary. For some reason AnyRef is not a package, object, trait, or class
val entry = entities.head
placeholderSeq ++ createLink(entry, includePlaceholder = false, includeText = true)
}
firstLink ++ createLink(template, includePlaceholder = false, includeText = true)

<li title={ entities.head.qualifiedName }>{
itemContents
}</li>
case _ => // FIXME: this default case should not be necessary. For some reason AnyRef is not a package, object, trait, or class
val entry = entities.head
placeholderSeq ++ createLink(entry, includePlaceholder = false, includeText = true)
}
}</ol>
<ol class="packages"> {
for (sp <- pack.packages sortBy (_.name.toLowerCase)) yield
<li class="pack" title={ sp.qualifiedName }>{ packageElem(sp) }</li>
}</ol>
</xml:group>
}
packageElem(universe.rootPackage)
}</div>
</div>
</body>

<li title={ entities.head.qualifiedName }>{
itemContents
}</li>
}
}</ol>
<ol class="packages"> {
for (sp <- pack.packages sortBy (_.name.toLowerCase)) yield
<li class="pack" title={ sp.qualifiedName }>{ packageElem(sp) }</li>
}</ol>
</xml:group>
}
packageElem(universe.rootPackage)
}</div>
</div>

def packageQualifiedName(ety: DocTemplateEntity): String =
if (ety.inTemplate.isPackage) ety.name else (packageQualifiedName(ety.inTemplate) + "." + ety.name)
Expand Down
Loading

0 comments on commit 16adcd1

Please sign in to comment.