diff options
author | Felix Mulder <felix.mulder@gmail.com> | 2016-05-30 17:45:32 +0200 |
---|---|---|
committer | Felix Mulder <felix.mulder@gmail.com> | 2016-08-19 15:37:24 +0200 |
commit | 59055f28c7f6f3b01216ccbbd701e138101912d3 (patch) | |
tree | c5aee716316c5d34bb215a5a2f4eec22afc90a42 | |
parent | 926a81c358b58ea09de86f8d55519cc38bc97034 (diff) | |
download | dotty-59055f28c7f6f3b01216ccbbd701e138101912d3.tar.gz dotty-59055f28c7f6f3b01216ccbbd701e138101912d3.tar.bz2 dotty-59055f28c7f6f3b01216ccbbd701e138101912d3.zip |
Add basic member-lookup for result types
12 files changed, 155 insertions, 56 deletions
diff --git a/dottydoc/js/src/html/Member.scala b/dottydoc/js/src/html/Member.scala index a862ffea4..ff16631c5 100644 --- a/dottydoc/js/src/html/Member.scala +++ b/dottydoc/js/src/html/Member.scala @@ -9,6 +9,7 @@ import org.scalajs.dom.html.{Anchor, Div} trait MemberLayout { import model._ + import comment._ def member(m: Entity, parent: Entity) = { def toggleBetween(short: Div, and: Div): Unit = @@ -66,9 +67,15 @@ trait MemberLayout { case xs => s } + def link(rv: MaterializableLink) = rv match { + case ml: MaterializedLink => + span(cls := "return-value", ": ", raw(ml.target)) + case un: UnsetLink => + span(cls := "return-value", ": " + shorten(un.query)) + } + m match { - case v: Val => span(cls := "return-value", ": " + shorten(v.returnValue)) - case d: Def => span(cls := "return-value", ": " + shorten(d.returnValue)) + case rv: ReturnValue => link(rv.returnValue) case _ => span() } } diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/core/Phases.scala b/dottydoc/jvm/src/dotty/tools/dottydoc/core/Phases.scala index 81dc21bbc..e4da0a971 100644 --- a/dottydoc/jvm/src/dotty/tools/dottydoc/core/Phases.scala +++ b/dottydoc/jvm/src/dotty/tools/dottydoc/core/Phases.scala @@ -13,7 +13,7 @@ import dotc.core.Symbols.Symbol object Phases { class DocPhase extends Phase { - import model.CommentParsers.WikiParser + import model.parsers.{ WikiParser, ReturnTypeParser } import model._ import model.factories._ import model.internal._ @@ -26,6 +26,7 @@ object Phases { def phaseName = "docphase" private[this] val commentParser = new WikiParser + private[this] val returnLinker = new ReturnTypeParser /** Saves the commentParser function for later evaluation, for when the AST has been filled */ def track(symbol: Symbol, ctx: Context)(op: => Entity) = { @@ -79,11 +80,11 @@ object Phases { /** def */ case d: DefDef => - DefImpl(filteredName(d.name.toString), flags(d), path(d), returnType(d.tpt)) + DefImpl(filteredName(d.name.toString), flags(d), path(d), returnType(d, d.tpt)) /** val */ case v: ValDef if !v.symbol.is(Flags.ModuleVal) => - ValImpl(filteredName(v.name.toString), flags(v), path(v), returnType(v.tpt)) + ValImpl(filteredName(v.name.toString), flags(v), path(v), returnType(v, v.tpt)) case x => { //dottydoc.println(s"Found unwanted entity: $x (${x.pos},\n${x.show}") @@ -137,6 +138,10 @@ object Phases { child <- parent.children } setParent(child, to = parent) + + // (3) Set returntypes to correct entities + returnLinker.link(packages) + // (3) Create documentation template from docstrings, with internal links println("Generating documentation, this might take a while...") commentParser.parse(packages) diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/BodyParsers.scala b/dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/BodyParsers.scala index 725d83557..8c1fa8d49 100644 --- a/dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/BodyParsers.scala +++ b/dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/BodyParsers.scala @@ -6,37 +6,7 @@ object BodyParsers { implicit class BodyToHtml(val body: Body) extends AnyVal { def toHtml(origin: Entity): String = { - def inlineToHtml(inl: Inline): String = inl match { - case Chain(items) => (items map inlineToHtml).mkString - case Italic(in) => s"<i>${inlineToHtml(in)}</i>" - case Bold(in) => s"<b>${inlineToHtml(in)}</b>" - case Underline(in) => s"<u>${inlineToHtml(in)}</u>" - case Superscript(in) => s"<sup>${inlineToHtml(in)}</sup>" - case Subscript(in) => s"<sub>${inlineToHtml(in) }</sub>" - case Link(raw, title) => s"""<a href=$raw target="_blank">${inlineToHtml(title)}</a>""" - case Monospace(in) => s"<code>${inlineToHtml(in)}</code>" - case Text(text) => text - case Summary(in) => inlineToHtml(in) - case HtmlTag(tag) => tag - case EntityLink(target, link) => enityLinkToHtml(target, link) - } - - def enityLinkToHtml(target: Inline, link: LinkTo) = link match { - case Tooltip(_) => inlineToHtml(target) - case LinkToExternal(n, url) => s"""<a href="$url">$n</a>""" - case LinkToEntity(t: Entity) => t match { - // Entity is a package member - case e: Entity with Members => - s"""<a href="${relativePath(t)}">${inlineToHtml(target)}</a>""" - // Entity is a Val / Def - case x => x.parent.fold(inlineToHtml(target)) { xpar => - s"""<a href="${relativePath(xpar)}#${x.name}">${inlineToHtml(target)}</a>""" - } - } - } - - def relativePath(target: Entity) = - util.traversing.relativePath(origin, target) + val inlineToHtml = InlineToHtml(origin) def bodyToHtml(body: Body): String = (body.blocks map blockToHtml).mkString @@ -73,4 +43,40 @@ object BodyParsers { bodyToHtml(body) } } + + case class InlineToHtml(origin: Entity) { + def apply(inline: Inline) = toHtml(inline) + + def relativePath(target: Entity) = + util.traversing.relativePath(origin, target) + + def toHtml(inline: Inline): String = inline match { + case Chain(items) => (items map toHtml).mkString + case Italic(in) => s"<i>${toHtml(in)}</i>" + case Bold(in) => s"<b>${toHtml(in)}</b>" + case Underline(in) => s"<u>${toHtml(in)}</u>" + case Superscript(in) => s"<sup>${toHtml(in)}</sup>" + case Subscript(in) => s"<sub>${toHtml(in) }</sub>" + case Link(raw, title) => s"""<a href=$raw target="_blank">${toHtml(title)}</a>""" + case Monospace(in) => s"<code>${toHtml(in)}</code>" + case Text(text) => text + case Summary(in) => toHtml(in) + case HtmlTag(tag) => tag + case EntityLink(target, link) => enityLinkToHtml(target, link) + } + + def enityLinkToHtml(target: Inline, link: LinkTo) = link match { + case Tooltip(_) => toHtml(target) + case LinkToExternal(n, url) => s"""<a href="$url">$n</a>""" + case LinkToEntity(t: Entity) => t match { + // Entity is a package member + case e: Entity with Members => + s"""<a href="${relativePath(t)}">${toHtml(target)}</a>""" + // Entity is a Val / Def + case x => x.parent.fold(toHtml(target)) { xpar => + s"""<a href="${relativePath(xpar)}#${x.name}">${toHtml(target)}</a>""" + } + } + } + } } diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/model/CommentParsers.scala b/dottydoc/jvm/src/dotty/tools/dottydoc/model/parsers.scala index 9320bb5fe..8d5eb3467 100644 --- a/dottydoc/jvm/src/dotty/tools/dottydoc/model/CommentParsers.scala +++ b/dottydoc/jvm/src/dotty/tools/dottydoc/model/parsers.scala @@ -4,11 +4,13 @@ package model import dotc.core.Symbols.Symbol import dotc.core.Contexts.Context +import dotc.util.Positions.NoPosition -object CommentParsers { +object parsers { import comment._ import BodyParsers._ import model.internal._ + import util.MemberLookup import util.traversing._ import util.internal.setters._ @@ -81,4 +83,22 @@ object CommentParsers { def clear(): Unit = commentCache = Map.empty } + + class ReturnTypeParser extends MemberLookup { + def link(packs: Map[String, Package]): Unit = + for (pack <- packs.values) mutateEntities(pack) { ent => + if (ent.isInstanceOf[ReturnValue]) + setReturnValue(ent, returnValue(ent, ent.asInstanceOf[ReturnValue], packs)) + } + + private def returnValue(ent: Entity, rv: ReturnValue, packs: Map[String, Package]): MaterializableLink = { + if (rv.returnValue.isInstanceOf[UnsetLink]) { + val unset = rv.returnValue.asInstanceOf[UnsetLink] + val el = makeEntityLink(ent, packs, unset.title, NoPosition, unset.query) + val inlineToHtml = InlineToHtml(ent) + + MaterializedLink(inlineToHtml(unset.title), inlineToHtml(el)) + } else rv.returnValue + } + } } diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/util/MemberLookup.scala b/dottydoc/jvm/src/dotty/tools/dottydoc/util/MemberLookup.scala index f95829caf..d8abb0319 100644 --- a/dottydoc/jvm/src/dotty/tools/dottydoc/util/MemberLookup.scala +++ b/dottydoc/jvm/src/dotty/tools/dottydoc/util/MemberLookup.scala @@ -30,7 +30,12 @@ trait MemberLookup { /** Looks for the specified entity among `ent`'s members */ def localLookup(ent: Entity with Members, searchStr: String): LinkTo = - ent.members.find(_.name == searchStr).fold(notFound)(e => LinkToEntity(e)) + ent + .members + .collect { case x if x.name == searchStr => x } + .sortBy(_.path.last) + .headOption + .fold(notFound)(e => LinkToEntity(e)) /** Looks for an entity down in the structure, if the search list is Nil, * the search stops @@ -43,8 +48,8 @@ trait MemberLookup { case x :: xs => ent .members - .collect { case e: Entity with Members => e } - .find(_.name == x) + .collect { case e: Entity with Members if e.name == x => e } + .headOption .fold(notFound)(e => downwardLookup(e, xs)) } @@ -71,8 +76,10 @@ trait MemberLookup { localLookup(e, x) case (x :: _, e: Entity with Members) if x == entity.name => downwardLookup(e, querys) - case _ => - globalLookup + case (x :: xs, _) => + if (xs.nonEmpty) + globalLookup + else lookup(entity, packages, "scala." + query, pos) } } @@ -82,5 +89,5 @@ trait MemberLookup { title: Inline, pos: Position, query: String - ): Inline = EntityLink(title, lookup(entity, packages, query, pos)) + ): EntityLink = EntityLink(title, lookup(entity, packages, query, pos)) } diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/util/mutate.scala b/dottydoc/jvm/src/dotty/tools/dottydoc/util/mutate.scala index 798d54041..bbef32474 100644 --- a/dottydoc/jvm/src/dotty/tools/dottydoc/util/mutate.scala +++ b/dottydoc/jvm/src/dotty/tools/dottydoc/util/mutate.scala @@ -4,8 +4,8 @@ package internal object setters { import model._ - import model.comment.Comment - import model.internal._ + import comment.{ Comment, MaterializableLink } + import internal._ def setComment(ent: Entity, to: Option[Comment]) = ent match { case x: PackageImpl => x.comment = to @@ -17,6 +17,13 @@ object setters { case x: ValImpl => x.comment = to } + + def setReturnValue(ent: Entity, to: MaterializableLink) = ent match { + case x: DefImpl => x.returnValue = to + case x: ValImpl => x.returnValue = to + case _ => () + } + def setParent(ent: Entity, to: Entity): Unit = ent match { case e: ClassImpl => e.parent = to diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/BodyEntities.scala b/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/comment/BodyEntities.scala index f423cf8de..c22d7a82f 100644 --- a/dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/BodyEntities.scala +++ b/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/comment/BodyEntities.scala @@ -87,6 +87,15 @@ final case class HtmlTag(data: String) extends Inline { final case class Summary(text: Inline) extends Inline sealed trait LinkTo -final case class LinkToEntity(entity: Entity) extends LinkTo final case class LinkToExternal(name: String, url: String) extends LinkTo final case class Tooltip(name: String) extends LinkTo + +/** Linking directly to entities is not picklable because of cyclic references */ +final case class LinkToEntity(entity: Entity) extends LinkTo + +/** Use MaterializableLink for entities that need be picklable */ +sealed trait MaterializableLink { + def title: Any +} +final case class UnsetLink(title: Inline, query: String) extends MaterializableLink +final case class MaterializedLink(title: String, target: String) extends MaterializableLink diff --git a/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/entities.scala b/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/entities.scala index e62b8573a..0ecfd04be 100644 --- a/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/entities.scala +++ b/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/entities.scala @@ -1,7 +1,7 @@ package dotty.tools.dottydoc package model -import comment.Comment +import comment.{ Comment, MaterializableLink } trait Entity { def name: String @@ -40,7 +40,7 @@ trait Modifiers { } trait ReturnValue { - def returnValue: String + def returnValue: MaterializableLink } trait Package extends Entity with Members { diff --git a/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/factories.scala b/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/factories.scala index 4707fccff..ab6ff86d1 100644 --- a/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/factories.scala +++ b/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/factories.scala @@ -1,6 +1,7 @@ package dotty.tools.dottydoc package model +import comment._ import dotty.tools.dotc import dotc.core.Types._ import dotc.core.Contexts.Context @@ -8,10 +9,13 @@ import dotc.core.Symbols.Symbol import dotc.core.{ Flags => DottyFlags } import dotc.ast.Trees._ + object factories { import dotty.tools.dotc.ast.tpd._ import DottyFlags._ + type TypeTree = dotty.tools.dotc.ast.Trees.Tree[Type] + def flags(t: Tree)(implicit ctx: Context): List[String] = (t.symbol.flags & SourceModifierFlags) .flagStrings.toList @@ -37,11 +41,23 @@ object factories { pathList(ref) } - // TODO: should be updated to link to local entities - def returnType(t: Tree)(implicit ctx: Context): String = - t.show + def returnType(t: Tree, tpt: TypeTree)(implicit ctx: Context): MaterializableLink = { + def cleanTitle(title: String): String = title match { + case x if x matches "[^\\[]+\\.this\\..+" => x.split("\\.").last + case _ => title + } + + def cleanQuery(query: String): String = query match { + case x if x matches "[^\\[]+\\[[^\\]]+\\]" => x.takeWhile(_ != '[') + case _ => query + } + + UnsetLink(Text(cleanTitle(tpt.show)), cleanQuery(tpt.show)) + } def filteredName(str: String) = str .replaceAll("\\$colon", ":") .replaceAll("\\$plus", "+") + .replaceAll("\\$less", "<") + .replaceAll("\\$eq", "=") } diff --git a/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/internal.scala b/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/internal.scala index 147523662..7535504b6 100644 --- a/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/internal.scala +++ b/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/internal.scala @@ -1,7 +1,7 @@ package dotty.tools.dottydoc package model -import comment.Comment +import comment.{ Comment, MaterializableLink } object internal { @@ -55,7 +55,7 @@ object internal { name: String, modifiers: List[String], path: List[String], - returnValue: String, + var returnValue: MaterializableLink, var comment: Option[Comment] = None ) extends Def with Impl @@ -63,7 +63,7 @@ object internal { name: String, modifiers: List[String], path: List[String], - returnValue: String, + var returnValue: MaterializableLink, var comment: Option[Comment] = None ) extends Val with Impl } diff --git a/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/pickling.scala b/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/pickling.scala index ea33a05fd..75741bb6b 100644 --- a/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/pickling.scala +++ b/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/pickling.scala @@ -4,6 +4,22 @@ package model object pickling { import internal._ import prickle._ + import comment._ + + implicit val inlinePickler: PicklerPair[Inline] = CompositePickler[Inline] + .concreteType[Chain] + .concreteType[Italic] + .concreteType[Bold] + .concreteType[Underline] + .concreteType[Superscript] + .concreteType[Subscript] + .concreteType[Link] + .concreteType[Monospace] + .concreteType[Text] + + implicit val entityLinkPicker: PicklerPair[MaterializableLink] = CompositePickler[MaterializableLink] + .concreteType[UnsetLink] + .concreteType[MaterializedLink] implicit val entityPickler: PicklerPair[Entity] = CompositePickler[Entity] .concreteType[NonEntity.type] diff --git a/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/util/Traversing.scala b/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/util/Traversing.scala index aca5f41ea..2ac8eae4f 100644 --- a/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/util/Traversing.scala +++ b/dottydoc/shared/src/main/scala/dotty/tools/dottydoc/util/Traversing.scala @@ -11,7 +11,13 @@ object traversing { case e: Entity => trans(e) } - def relativePath(from: Entity, to: Entity) = - "../" * (from.path.length - 1) + + def relativePath(from: Entity, to: Entity) = { + val offset = from match { + case _: Val | _: Def => 2 + case _ => 1 + } + + "../" * (from.path.length - offset) + to.path.mkString("", "/", ".html") + } } |