summaryrefslogtreecommitdiff
path: root/src/compiler/scala
diff options
context:
space:
mode:
authorGilles Dubochet <gilles.dubochet@epfl.ch>2010-02-03 17:03:58 +0000
committerGilles Dubochet <gilles.dubochet@epfl.ch>2010-02-03 17:03:58 +0000
commita6eecfb04532c83a715d520e885250e8de808f9e (patch)
treecbfbf98476467a63c3e28652e767a431655ca46e /src/compiler/scala
parent909924acba60dadee5647e405c0bb9a2676f4a70 (diff)
downloadscala-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.
Diffstat (limited to 'src/compiler/scala')
-rw-r--r--src/compiler/scala/tools/ant/Scaladoc.scala20
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala16
-rw-r--r--src/compiler/scala/tools/nsc/doc/Settings.scala4
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/Template.scala57
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/Entity.scala4
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala35
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala6
7 files changed, 93 insertions, 49 deletions
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