diff options
author | Gilles Dubochet <gilles.dubochet@epfl.ch> | 2010-02-03 17:03:58 +0000 |
---|---|---|
committer | Gilles Dubochet <gilles.dubochet@epfl.ch> | 2010-02-03 17:03:58 +0000 |
commit | a6eecfb04532c83a715d520e885250e8de808f9e (patch) | |
tree | cbfbf98476467a63c3e28652e767a431655ca46e | |
parent | 909924acba60dadee5647e405c0bb9a2676f4a70 (diff) | |
download | scala-a6eecfb04532c83a715d520e885250e8de808f9e.tar.gz scala-a6eecfb04532c83a715d520e885250e8de808f9e.tar.bz2 scala-a6eecfb04532c83a715d520e885250e8de808f9e.zip |
[scaladoc] Optional link to source (set paramet...
[scaladoc] Optional link to source (set parameter "-doc-source-url").
Support for commenting packages (using package objects). Contributed by
Perdo Furlanetto. Also: small performance improvements, short comment
extraction is more robust (but no HTML tags allowed in first sentence),
small code clean-ups. Checked by dubochet, no review.
-rw-r--r-- | build.xml | 11 | ||||
-rw-r--r-- | src/compiler/scala/tools/ant/Scaladoc.scala | 20 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 16 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/Settings.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/html/page/Template.scala | 57 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/model/Entity.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala | 35 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala | 6 |
8 files changed, 102 insertions, 51 deletions
@@ -1269,7 +1269,10 @@ DOCUMENTATION <mkdir dir="${build-docs.dir}/library"/> <scaladoc destdir="${build-docs.dir}/library" - doctitle="Scala ${version.number} API" + doctitle="Scala Standard Libray" + docversion="${version.number}" + docsourceurl="https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/" + sourcepath="${src.dir}" classpathref="pack.classpath"> <src> <files includes="${src.dir}/actors"/> @@ -1289,6 +1292,7 @@ DOCUMENTATION <exclude name="runtime/ScalaRunTime.scala"/> <exclude name="runtime/StreamCons.scala"/> <exclude name="runtime/StringAdd.scala"/> + <exclude name="scala/swing/test/**"/> </scaladoc> <touch file="${build-docs.dir}/library.complete" verbose="no"/> <stopwatch name="docs.lib.timer" action="total"/> @@ -1351,7 +1355,10 @@ DOCUMENTATION <mkdir dir="${build-docs.dir}/compiler"/> <scaladoc destdir="${build-docs.dir}/compiler" - doctitle="Scala Compiler ${version.number} API" + doctitle="Scala Compiler" + docversion="${version.number}" + docsourceurl="https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/" + sourcepath="${src.dir}" classpathref="pack.classpath" srcdir="${src.dir}/compiler"> <include name="**/*.scala"/> diff --git a/src/compiler/scala/tools/ant/Scaladoc.scala b/src/compiler/scala/tools/ant/Scaladoc.scala index 78093ae95a..31463d620d 100644 --- a/src/compiler/scala/tools/ant/Scaladoc.scala +++ b/src/compiler/scala/tools/ant/Scaladoc.scala @@ -107,6 +107,9 @@ class Scaladoc extends MatchingTask { /** The document version, to be added to the title. */ private var docversion: Option[String] = None + /** Instruct the compiler to generate links to sources */ + private var docsourceurl: Option[String] = None + /** Instruct the compiler to use additional parameters */ private var addParams: String = "" @@ -264,6 +267,22 @@ class Scaladoc extends MatchingTask { encoding = Some(input) } + /** Sets the <code>docversion</code> attribute. + * + * @param input The value of <code>docversion</code>. + */ + def setDocversion(input: String) { + docversion = Some(input) + } + + /** Sets the <code>docsourceurl</code> attribute. + * + * @param input The value of <code>docsourceurl</code>. + */ + def setDocsourceurl(input: String) { + docsourceurl = Some(input) + } + /** Sets the <code>doctitle</code> attribute. * * @param input The value of <code>doctitle</code>. @@ -497,6 +516,7 @@ class Scaladoc extends MatchingTask { if (!encoding.isEmpty) docSettings.encoding.value = encoding.get if (!doctitle.isEmpty) docSettings.doctitle.value = decodeEscapes(doctitle.get) if (!docversion.isEmpty) docSettings.docversion.value = decodeEscapes(docversion.get) + if (!docsourceurl.isEmpty) docSettings.docsourceurl.value =decodeEscapes(docsourceurl.get) docSettings.deprecation.value = deprecation docSettings.unchecked.value = unchecked log("Scaladoc params = '" + addParams + "'", Project.MSG_DEBUG) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 58552e18e5..117fbde419 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2469,11 +2469,15 @@ self => val stats = new ListBuffer[Tree] while (in.token != RBRACE && in.token != EOF) { if (in.token == PACKAGE) { - in.flushDoc val start = in.skipToken() - stats += { - if (in.token == OBJECT) makePackageObject(start, objectDef(in.offset, NoMods)) - else packaging(start) + stats ++= { + if (in.token == OBJECT) { + joinComment(List(makePackageObject(start, objectDef(in.offset, NoMods)))) + } + else { + in.flushDoc + List(packaging(start)) + } } } else if (in.token == IMPORT) { in.flushDoc @@ -2631,15 +2635,15 @@ self => while (in.token == SEMI) in.nextToken() val start = in.offset if (in.token == PACKAGE) { - in.flushDoc in.nextToken() if (in.token == OBJECT) { - ts += makePackageObject(start, objectDef(in.offset, NoMods)) + ts ++= joinComment(List(makePackageObject(start, objectDef(in.offset, NoMods)))) if (in.token != EOF) { acceptStatSep() ts ++= topStatSeq() } } else { + in.flushDoc val pkg = qualId() newLineOptWhenFollowedBy(LBRACE) if (in.token == EOF) { diff --git a/src/compiler/scala/tools/nsc/doc/Settings.scala b/src/compiler/scala/tools/nsc/doc/Settings.scala index 75aff8e4bd..0ea17970f6 100644 --- a/src/compiler/scala/tools/nsc/doc/Settings.scala +++ b/src/compiler/scala/tools/nsc/doc/Settings.scala @@ -26,6 +26,10 @@ class Settings(error: String => Unit) extends scala.tools.nsc.Settings(error) { * documented. 'Note:'' This setting is currently not used. */ val docversion = StringSetting ("-doc-version", "doc-version", "An optional version number, to be appended to the title", "") + /** A setting that defines a URL to be concatenated with source locations and show a link to source files. + * If needed the sourcepath option can be used to exclude undesired initial part of the link to sources */ + val docsourceurl = StringSetting ("-doc-source-url", "url", "The URL prefix where documentation will link to sources", "") + // working around issue described in r18708. suppressVTWarn.value = true 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 185288ace8..786189d655 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -170,6 +170,15 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { attributes: { fvs map { fv => { inlineToHtml(fv.text) ++ xml.Text(" ") } } } </div> } + { tpl.companion match { + case Some(companion) if isSelf => + <div class="block"> + Go to: <a href={relativeLinkTo(companion)}>companion</a> + </div> + case _ => + NodeSeq.Empty + } + } { val inDefTpls = mbr.inDefinitionTemplates if (inDefTpls.tail.isEmpty && (inDefTpls.head == mbr.inTemplate)) NodeSeq.Empty else { <div class="block"> @@ -178,29 +187,29 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { } } { mbr match { - case dtpl: DocTemplateEntity if isSelf => - val subClss = dtpl.subClasses - if (subClss.isEmpty) NodeSeq.Empty else - <div class="block"> - known subclasses: { templatesToHtml(dtpl.subClasses, xml.Text(", ")) } - </div> + case dtpl: DocTemplateEntity if (isSelf && !dtpl.subClasses.isEmpty) => + <div class="block"> + known subclasses: { templatesToHtml(dtpl.subClasses, xml.Text(", ")) } + </div> case _ => NodeSeq.Empty } } + { mbr match { + case dtpl: DocTemplateEntity if (isSelf && dtpl.sourceUrl.isDefined) => + val sourceUrl = tpl.sourceUrl.get + <div class="block"> + source: { <a href={ sourceUrl.toString }>{ Text(new java.io.File(sourceUrl.getPath).getName) }</a> } + </div> + case _ => NodeSeq.Empty + } + } + { if(mbr.deprecation.isEmpty) NodeSeq.Empty else + <div class="block"><ol>deprecated: + { <li>{ bodyToHtml(mbr.deprecation.get) }</li> } + </ol></div> + } { for(comment <- mbr.comment.toList) yield { <xml:group> - { if(!comment.deprecated.isEmpty) - <div class="block"><ol>deprecated: - { for(body <- comment.deprecated.toList) yield <li>{bodyToHtml(body)}</li> } - </ol></div> - else NodeSeq.Empty - } - { if(mbr.isDeprecated) - <div class="block"><ol>deprecated: - { for(str <- mbr.deprecationMessage.toList) yield <li>{str}</li> } - </ol></div> - else NodeSeq.Empty - } { if(!comment.version.isEmpty) <div class="block"><ol>version { for(body <- comment.version.toList) yield <li>{bodyToHtml(body)}</li> } @@ -231,15 +240,6 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { } </xml:group> }} - { tpl.companion match { - case Some(companion) if isSelf => - <div class="block"> - Go to: <a href={relativeLinkTo(companion)}>companion</a> - </div> - case _ => - NodeSeq.Empty - } - } </xml:group> def kindToString(mbr: MemberEntity): String = mbr match { @@ -260,12 +260,11 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { /** name, tparams, params, result */ def signature(mbr: MemberEntity, isSelf: Boolean): NodeSeq = { - val isDeprecated = mbr.isDeprecated || (!mbr.comment.isEmpty && !mbr.comment.get.deprecated.isEmpty) def inside(hasLinks: Boolean): NodeSeq = <xml:group> <span class="kind">{ kindToString(mbr) }</span> <span class="symbol"> - <span class={"name" + (if(isDeprecated) " deprecated" else "") }>{ if (mbr.isConstructor) tpl.name else mbr.name }</span>{ + <span class={"name" + (if (mbr.deprecation.isDefined) " deprecated" else "") }>{ if (mbr.isConstructor) tpl.name else mbr.name }</span>{ def tparamsToHtml(tpss: List[TypeParam]): NodeSeq = if (tpss.isEmpty) NodeSeq.Empty else { def tparam0(tp: TypeParam): NodeSeq = diff --git a/src/compiler/scala/tools/nsc/doc/model/Entity.scala b/src/compiler/scala/tools/nsc/doc/model/Entity.scala index 53ac6740cf..7be902cd5f 100644 --- a/src/compiler/scala/tools/nsc/doc/model/Entity.scala +++ b/src/compiler/scala/tools/nsc/doc/model/Entity.scala @@ -43,9 +43,8 @@ trait MemberEntity extends Entity { def definitionName: String def visibility: Option[Paragraph] def flags: List[Paragraph] + def deprecation: Option[Body] def inheritedFrom: List[TemplateEntity] - def isDeprecated: Boolean - def deprecationMessage: Option[String] def resultType: TypeEntity def isDef: Boolean def isVal: Boolean @@ -61,6 +60,7 @@ trait MemberEntity extends Entity { trait DocTemplateEntity extends TemplateEntity with MemberEntity { def toRoot: List[DocTemplateEntity] def inSource: Option[(io.AbstractFile, Int)] + def sourceUrl: Option[java.net.URL] def typeParams: List[TypeParam] def parentType: Option[TypeEntity] def linearization: List[TemplateEntity] diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 434e2b4572..bf18f28f75 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -25,7 +25,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = object commentator { - private val factory = new CommentFactory(reporter) + val factory = new CommentFactory(reporter) private val commentCache = mutable.HashMap.empty[(Symbol, TemplateImpl), Comment] @@ -94,8 +94,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = def inDefinitionTemplates = if (inTpl == null) makePackage(RootPackage, null).toList - else if (sym.owner == inTpl.sym) - inTpl :: Nil else makeTemplate(sym.owner) :: (sym.allOverriddenSymbols map { inhSym => makeTemplate(inhSym.owner) }) def visibility = { @@ -121,11 +119,18 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = if (!sym.isModule && (sym hasFlag Flags.FINAL)) fgs += Paragraph(Text("final")) fgs.toList } + def deprecation = + if (sym.isDeprecated && sym.deprecationMessage.isDefined) + Some(commentator.factory.parseWiki(sym.deprecationMessage.get, NoPosition)) + else if (sym.isDeprecated) + Some(Body(Nil)) + else if (comment.isDefined) + comment.get.deprecated + else + None def inheritedFrom = if (inTemplate.sym == this.sym.owner || inTemplate.sym.isPackage) Nil else makeTemplate(this.sym.owner) :: (sym.allOverriddenSymbols map { os => makeTemplate(os.owner) }) - def isDeprecated = sym.isDeprecated - def deprecationMessage = sym.deprecationMessage def resultType = makeType(sym.tpe.finalResultType, inTemplate, sym) def isDef = false def isVal = false @@ -150,6 +155,18 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = override def definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "." + name) override def toRoot: List[DocTemplateImpl] = this :: inTpl.toRoot def inSource = if (sym.sourceFile != null) Some(sym.sourceFile, sym.pos.line) else None + def sourceUrl = { + def fixPath(s: String) = s.replaceAll(java.io.File.separator, "/") + val assumedSourceRoot: String = { + val fixed = fixPath(settings.sourcepath.value) + if (fixed endsWith "/") fixed.dropRight(1) else fixed + } + if (!settings.docsourceurl.isDefault) + inSource map { case (file, _) => + new java.net.URL(settings.docsourceurl.value + "/" + fixPath(file.path).replaceFirst("^" + assumedSourceRoot, "")) + } + else None + } def typeParams = if (sym.isClass) sym.typeParams map (makeTypeParam(_, this)) else Nil def parentType = if (sym.isPackage) None else @@ -169,7 +186,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = subClassesCache += sc } def subClasses = subClassesCache.toList - protected def memberSyms = + protected lazy val memberSyms = // Only this class's constructors are part of its members, inherited constructors are not. sym.info.nonPrivateMembers.filter(x => (!x.isConstructor || x.owner==sym)) val members = memberSyms flatMap (makeMember(_, this)) @@ -231,7 +248,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = override def qualifiedName = "_root_" override def inheritedFrom = Nil override def isRootPackage = true - override protected def memberSyms = + override protected lazy val memberSyms = (bSym.info.members ++ EmptyPackage.info.members) filter { s => s != EmptyPackage && s != RootPackage } @@ -358,13 +375,13 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = }) else if (bSym.isPackage) inTpl match { case inPkg: PackageImpl => makePackage(bSym, inPkg) } - else if ((bSym.isClass || bSym.isModule) && (bSym.sourceFile != null) && bSym.isPublic && !bSym.isLocal) { + else if ((bSym.isClass || bSym.isModule) && bSym.isPublic && !bSym.isLocal) { (inTpl.toRoot find (_.sym == bSym )) orElse Some(makeDocTemplate(bSym, inTpl)) } else None } - if (!aSym.isPublic || (aSym hasFlag Flags.SYNTHETIC) || (aSym hasFlag Flags.BRIDGE) || aSym.isLocal || aSym.isModuleClass || aSym.isPackageObject || aSym.isMixinConstructor) + if ((!aSym.isPackage && aSym.sourceFile == null) || !aSym.isPublic || (aSym hasFlag Flags.SYNTHETIC) || aSym.isLocal || aSym.isModuleClass || aSym.isPackageObject || aSym.isMixinConstructor) Nil else { val allSyms = useCases(aSym, inTpl.sym) map { case (bSym, bComment, bPos) => diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala index 3fb8e4643c..05064d362a 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -29,10 +29,10 @@ final class CommentFactory(val reporter: Reporter) { parser => throw FatalError("program logic: " + msg) protected val CleanHtml = - new Regex("""</?(p|h\d|pre|dl|dt|dd|ol|ul|li|blockquote|div|hr|br|br)\s*/?>""") + new Regex("""</?(p|h\d|pre|dl|dt|dd|ol|ul|li|blockquote|div|hr|br|br).*/?>""") protected val ShortLineEnd = - new Regex("""\.|</(p|h\d|pre|dd|li|div|blockquote)>|<(hr|table)\s*/?>""") + new Regex("""\.|</?.*>""") /** The body of a comment, dropping start and end markers. */ protected val CleanComment = @@ -220,7 +220,7 @@ final class CommentFactory(val reporter: Reporter) { parser => * * Removed start-of-line star and one whitespace afterwards (if present). * * Removed all end-of-line whitespace. * * Only `endOfLine` is used to mark line endings. */ - protected def parseWiki(string: String, pos: Position): Body = + def parseWiki(string: String, pos: Position): Body = new WikiParser(string.toArray, pos).document() /** TODO |