From 25821bfc25685ab648dd6eb1a11d0f8991a07a75 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Wed, 18 Jan 2017 11:03:43 +0100 Subject: Rewire `MemberLookup` to return `Option[Entity]` This allows for the rendering engine to supply the base url for the site and thus being able to simplify the entity links. They now simply become `Entity#path + .html` instead of a convoluted rendering in the html renderers. --- doc-tool/resources/_layouts/api-page.html | 4 +- .../tools/dottydoc/core/TypeLinkingPhases.scala | 20 +-- .../tools/dottydoc/model/comment/Comment.scala | 9 +- .../tools/dottydoc/model/comment/HtmlParsers.scala | 4 +- .../tools/dottydoc/model/comment/WikiParser.scala | 2 +- .../src/dotty/tools/dottydoc/model/factories.scala | 1 + .../tools/dottydoc/staticsite/LiquidTemplate.scala | 32 +---- .../dotty/tools/dottydoc/staticsite/filters.scala | 92 -------------- .../src/dotty/tools/dottydoc/staticsite/tags.scala | 134 +++++++++++++++++++++ .../dotty/tools/dottydoc/util/MemberLookup.scala | 21 ++-- 10 files changed, 171 insertions(+), 148 deletions(-) create mode 100644 doc-tool/src/dotty/tools/dottydoc/staticsite/tags.scala (limited to 'doc-tool') diff --git a/doc-tool/resources/_layouts/api-page.html b/doc-tool/resources/_layouts/api-page.html index cfbb03352..280c81af5 100644 --- a/doc-tool/resources/_layouts/api-page.html +++ b/doc-tool/resources/_layouts/api-page.html @@ -62,7 +62,7 @@ extraCSS: {{ namedRef.title }}:{% if namedRef.isByName %} =>{% endif %} - {{ namedRef.ref | renderRef }} + {% renderRef namedRef.ref %} {% if forloop.last != true %} , {% endif %} @@ -74,7 +74,7 @@ extraCSS: {% if member.kind == "type" and member.alias != null %} = - {{ member.alias | renderRef }} + {% renderRef member.alias %} {% endif %} diff --git a/doc-tool/src/dotty/tools/dottydoc/core/TypeLinkingPhases.scala b/doc-tool/src/dotty/tools/dottydoc/core/TypeLinkingPhases.scala index 5b13930f2..245db060d 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/TypeLinkingPhases.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/TypeLinkingPhases.scala @@ -43,9 +43,7 @@ class LinkSuperTypes extends DocMiniPhase with TypeLinker { def linkSuperTypes(ent: Entity with SuperTypes)(implicit ctx: Context): List[MaterializableLink] = ent.superTypes.collect { case UnsetLink(title, query) => - val packages = ctx.docbase.packages - val entityLink = makeEntityLink(ent, packages, Text(title), NoPosition, query).link - handleEntityLink(title, entityLink, ent) + handleEntityLink(title, lookup(ent, ctx.docbase.packages, query), ent) } override def transformClass(implicit ctx: Context) = { case cls: ClassImpl => @@ -80,11 +78,15 @@ class LinkImplicitlyAddedTypes extends DocMiniPhase with TypeLinker { } trait TypeLinker extends MemberLookup { - def handleEntityLink(title: String, lt: LinkTo, ent: Entity): MaterializableLink = lt match { - case Tooltip(str) => NoLink(title, str) - case LinkToExternal(_, url) => MaterializedLink(title, url) - case LinkToEntity(target) => MaterializedLink(title, util.traversing.relativePath(ent, target)) - } + def handleEntityLink(title: String, target: Option[Entity], ent: Entity, query: String = ""): MaterializableLink = + target match { + case Some(target: Package) => + MaterializedLink(title, target.path.mkString("/") + "/index.html") + case Some(target) => + MaterializedLink(title, target.path.mkString("/") + ".html") + case none => + NoLink(title, query) + } def linkReference(ent: Entity, ref: Reference, packs: Map[String, Package]): Reference = { def linkRef(ref: Reference) = linkReference(ent, ref, packs) @@ -94,7 +96,7 @@ trait TypeLinker extends MemberLookup { val inlineToHtml = InlineToHtml(ent) val title = t - val target = handleEntityLink(title, makeEntityLink(ent, packs, Text(t), NoPosition, query).link, ent) + val target = handleEntityLink(title, lookup(ent, packs, query), ent, query) val tpTargets = tps.map(linkReference(ent, _, packs)) ref.copy(tpeLink = target, paramLinks = tpTargets) case ref @ OrTypeReference(left, right) => diff --git a/doc-tool/src/dotty/tools/dottydoc/model/comment/Comment.scala b/doc-tool/src/dotty/tools/dottydoc/model/comment/Comment.scala index 842746338..e50d2be90 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/comment/Comment.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/comment/Comment.scala @@ -62,9 +62,8 @@ object MarkdownComment extends util.MemberLookup { val inlineToHtml = InlineToHtml(ent) def linkedExceptions(m: Map[String, String]): Map[String, String] = { m.map { case (targetStr, body) => - val link = lookup(ent, ctx.docbase.packages, targetStr) - val entityLink = EntityLink(Monospace(Text(targetStr)), link) - (targetStr, inlineToHtml(entityLink)) + val link = makeEntityLink(ent, ctx.docbase.packages, Monospace(Text(targetStr)), targetStr) + (targetStr, inlineToHtml(link)) } } @@ -121,8 +120,8 @@ object WikiComment extends util.MemberLookup { val newBody = body match { case Body(List(Paragraph(Chain(content)))) => val descr = Text(" ") +: content - val entityLink = EntityLink(Monospace(Text(targetStr)), link) - Body(List(Paragraph(Chain(entityLink +: descr)))) + val link = makeEntityLink(ent, ctx.docbase.packages, Monospace(Text(targetStr)), targetStr) + Body(List(Paragraph(Chain(link +: descr)))) case _ => body } (targetStr, newBody) diff --git a/doc-tool/src/dotty/tools/dottydoc/model/comment/HtmlParsers.scala b/doc-tool/src/dotty/tools/dottydoc/model/comment/HtmlParsers.scala index 475157dce..4ddbfd6ab 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/comment/HtmlParsers.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/comment/HtmlParsers.scala @@ -37,7 +37,7 @@ object HtmlParsers { val linkVisitor = new NodeVisitor( new VisitHandler(classOf[Link], new Visitor[Link] with MemberLookup { - def queryToUrl(link: String) = lookup(origin, ctx.docbase.packages, link) match { + def queryToUrl(title: String, link: String) = makeEntityLink(origin, ctx.docbase.packages, Text(title), link).link match { case Tooltip(_) => "#" case LinkToExternal(_, url) => url case LinkToEntity(t: Entity) => t match { @@ -49,7 +49,7 @@ object HtmlParsers { override def visit(link: Link) = { val linkUrl = link.getUrl.toString if (!isOuter(linkUrl) && !isRelative(linkUrl)) - link.setUrl(CharSubSequence.of(queryToUrl(linkUrl))) + link.setUrl(CharSubSequence.of(queryToUrl(link.getTitle.toString, linkUrl))) } }) ) diff --git a/doc-tool/src/dotty/tools/dottydoc/model/comment/WikiParser.scala b/doc-tool/src/dotty/tools/dottydoc/model/comment/WikiParser.scala index 13d74d4b3..176dab569 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/comment/WikiParser.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/comment/WikiParser.scala @@ -335,7 +335,7 @@ private[comment] final class WikiParser( case (SchemeUri(uri), optTitle) => Link(uri, optTitle getOrElse Text(uri)) case (qualName, optTitle) => - makeEntityLink(entity, packages, optTitle getOrElse Text(target), pos, target) + makeEntityLink(entity, packages, optTitle getOrElse Text(target), target) } } diff --git a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala index 0f4df7640..568b532b7 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala @@ -26,6 +26,7 @@ object factories { .flagStrings.toList .filter(_ != "") .filter(_ != "interface") + .filter(_ != "case") def path(sym: Symbol)(implicit ctx: Context): List[String] = sym match { case sym if sym.name.decode.toString == "" => Nil diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/LiquidTemplate.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/LiquidTemplate.scala index a92e5d48e..a86a5bb54 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/LiquidTemplate.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/LiquidTemplate.scala @@ -6,18 +6,15 @@ import dotc.config.Printers.dottydoc case class LiquidTemplate(contents: String) extends ResourceFinder { import scala.collection.JavaConverters._ - import liqp.{ Template, TemplateContext } - import liqp.nodes.LNode - import liqp.tags.Tag + import liqp.Template import liqp.filters.Filter import liqp.parser.Flavor.JEKYLL import java.util.{ HashMap, Map => JMap } import filters._ + import tags._ /** Register filters to static container */ Filter.registerFilter(new Reverse) - Filter.registerFilter(new RenderReference) - Filter.registerFilter(new RenderLink) // For some reason, liqp rejects a straight conversion using `.asJava` private def toJavaMap(map: Map[String, AnyRef]): HashMap[String, Object] = @@ -29,29 +26,6 @@ case class LiquidTemplate(contents: String) extends ResourceFinder { def render(params: Map[String, AnyRef], includes: Map[String, String]): String = Template.parse(contents, JEKYLL) .`with`(ResourceInclude(params, includes)) + .`with`(RenderReference(params)) .render(toJavaMap(params)) - - private case class ResourceInclude(params: Map[String, AnyRef], includes: Map[String, String]) - extends Tag("include") { - val DefaultExtension = ".html" - - override def render(ctx: TemplateContext, nodes: LNode*): AnyRef = { - val origInclude = asString(nodes(0).render(ctx)) - val incResource = origInclude match { - case fileWithExt if fileWithExt.indexOf('.') > 0 => fileWithExt - case file => file + DefaultExtension - } - - includes - .get(incResource) - .map { template => - if (nodes.length > 1) ctx.put(origInclude, nodes(1).render(ctx)) - LiquidTemplate(template).render(Map.empty ++ ctx.getVariables.asScala, includes) - } - .getOrElse { - /*dottydoc.*/println(s"couldn't find include file '$origInclude'") - "" - } - } - } } diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/filters.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/filters.scala index a4662e735..2239f5a50 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/filters.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/filters.scala @@ -2,7 +2,6 @@ package dotty.tools package dottydoc package staticsite -import model.references._ import java.util.{ Map => JMap } import liqp.filters.Filter @@ -24,95 +23,4 @@ object filters { else array.reverse } } - - /** Renders a `Reference` as HTML. Example: - * - * ```html - * {{ ref | renderRef }} - * ``` - * - * where `ref` is: - * - * ```scala - * TypeReference("Seq", MaterializedLink("Seq", "../../scala/collection/Seq.html"), Nil) - * ``` - * - * will render: - * - * ```html - * Seq - * [ - * A - * ] - * ``` - */ - final class RenderReference extends Filter("renderRef") { - // might need to be rewritten to be stack safe - private def renderReference(ref: Reference): String = ref match { - case TypeReference(_, tpeLink, paramLinks) => { - if (paramLinks.nonEmpty) { - s"""|${renderLink(tpeLink)} - |[ - |${ paramLinks.map(renderReference).mkString(""", """) } - |]""".stripMargin - } - else renderLink(tpeLink) - } - - case AndOrTypeReference(left, sep, right) => - s"""${renderReference(left)} $sep ${renderReference(right)}""" - - case FunctionReference(args, returnValue) => { - val params = - if (args.isEmpty) "() => " - else if (args.tail.isEmpty) renderReference(args.head) + """ => """ - else args.map(renderReference).mkString("(", ", ", ") => ") - - params + renderReference(returnValue) - } - - case TupleReference(args) => - s"""|( - |${ args.map(renderReference).mkString(", ") } - |)""".stripMargin - - case BoundsReference(low, high) => - s"""${ renderReference(low) } <: ${ renderReference(high) }""" - - case NamedReference(title, _, _, _) => - /*dottydoc.*/println(s"received illegal named reference in rendering: $ref") - title - - case ConstantReference(title) => title - } - - override def apply(value: Any, params: AnyRef*): AnyRef = value match { - case value: JMap[String, _] @unchecked => - val ref = value.get("scala").asInstanceOf[Reference] - if (ref ne null) renderReference(ref) - else null - case _ => - /*dottydoc.*/println(s"couldn't render: '$value'") - null - } - } - - /** Renders a `MaterializableLink` into a HTML anchor tag. If the link is - * `NoLink` it will just return a string with the link's title. - */ - final class RenderLink extends Filter("renderLink") { - override def apply(value: Any, params: AnyRef*): AnyRef = value match { - case value: JMap[String, _] @unchecked => - renderLink(value.get("scala").asInstanceOf[MaterializableLink]) - case _ => - /*dottydoc.*/println(s"couldn't render: '$value'") - null - } - } - - private[this] def renderLink(link: MaterializableLink): String = link match { - case MaterializedLink(title, target) => - s"""$title""" - case _ => link.title - } } diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/tags.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/tags.scala new file mode 100644 index 000000000..868e28bce --- /dev/null +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/tags.scala @@ -0,0 +1,134 @@ +package dotty.tools +package dottydoc +package staticsite + +import model.references._ + +import liqp.tags.Tag +import liqp.TemplateContext +import liqp.nodes.LNode + +import java.util.{ Map => JMap } + +object tags { + + sealed trait ParamConverter { + def params: Map[String, AnyRef] + + val baseurl: String = + params.get("site").flatMap { + case map: JMap[String, String] @unchecked => + Some(map.get("baseurl")) + case _ => + None + } + .getOrElse { + /*dottydoc.*/println(s"missing `baseurl` in: $params") + "" + } + } + + /** Renders a `MaterializableLink` into a HTML anchor tag. If the link is + * `NoLink` it will just return a string with the link's title. + */ + final case class RenderLink(params: Map[String, AnyRef]) extends Tag("renderLink") with ParamConverter { + override def render(ctx: TemplateContext, nodes: LNode*): AnyRef = nodes(0).render(ctx) match { + case map: JMap[String, AnyRef] @unchecked => + val link = map.get("scala") + if (link.isInstanceOf[MaterializableLink] && (link ne null)) + renderLink(baseurl, link.asInstanceOf[MaterializableLink]) + else if (link eq null) + null // Option[Reference] was None + else { + /*dottydoc.*/println(s"illegal argument: $link, to `renderLink` function") + null + } + case _ => null + } + } + + + private[this] def renderLink(baseurl: String, link: MaterializableLink): String = link match { + case MaterializedLink(title, target) => + s"""$title""" + case _ => link.title + } + + final case class RenderReference(params: Map[String, AnyRef]) + extends Tag("renderRef") with ParamConverter { + + private def renderReference(ref: Reference): String = ref match { + case TypeReference(_, tpeLink, paramLinks) => { + if (paramLinks.nonEmpty) { + s"""|${renderLink(baseurl, tpeLink)} + |[ + |${ paramLinks.map(renderReference).mkString(""", """) } + |]""".stripMargin + } + else renderLink(baseurl, tpeLink) + } + + case AndOrTypeReference(left, sep, right) => + s"""${renderReference(left)} $sep ${renderReference(right)}""" + + case FunctionReference(args, returnValue) => { + val params = + if (args.isEmpty) "() => " + else if (args.tail.isEmpty) renderReference(args.head) + """ => """ + else args.map(renderReference).mkString("(", ", ", ") => ") + + params + renderReference(returnValue) + } + + case TupleReference(args) => + s"""|( + |${ args.map(renderReference).mkString(", ") } + |)""".stripMargin + + case BoundsReference(low, high) => + s"""${ renderReference(low) } <: ${ renderReference(high) }""" + + case NamedReference(title, _, _, _) => + /*dottydoc.*/println(s"received illegal named reference in rendering: $ref") + title + + case ConstantReference(title) => title + } + override def render(ctx: TemplateContext, nodes: LNode*): AnyRef = nodes(0).render(ctx) match { + case map: JMap[String, AnyRef] @unchecked => + val ref = map.get("scala") + if (ref.isInstanceOf[Reference] && (ref ne null)) renderReference(ref.asInstanceOf[Reference]) + else if (ref eq null) null // Option[Reference] was None + else { + /*dottydoc.*/println(s"illegal argument: $ref, to `renderRef` function") + null + } + case _ => null + } + } + + case class ResourceInclude(params: Map[String, AnyRef], includes: Map[String, String]) + extends Tag("include") { + import scala.collection.JavaConverters._ + val DefaultExtension = ".html" + + override def render(ctx: TemplateContext, nodes: LNode*): AnyRef = { + val origInclude = asString(nodes(0).render(ctx)) + val incResource = origInclude match { + case fileWithExt if fileWithExt.indexOf('.') > 0 => fileWithExt + case file => file + DefaultExtension + } + + includes + .get(incResource) + .map { template => + if (nodes.length > 1) ctx.put(origInclude, nodes(1).render(ctx)) + LiquidTemplate(template).render(Map.empty ++ ctx.getVariables.asScala, includes) + } + .getOrElse { + /*dottydoc.*/println(s"couldn't find include file '$origInclude'") + "" + } + } + } +} diff --git a/doc-tool/src/dotty/tools/dottydoc/util/MemberLookup.scala b/doc-tool/src/dotty/tools/dottydoc/util/MemberLookup.scala index caa57db52..7e37d0cfd 100644 --- a/doc-tool/src/dotty/tools/dottydoc/util/MemberLookup.scala +++ b/doc-tool/src/dotty/tools/dottydoc/util/MemberLookup.scala @@ -19,23 +19,22 @@ trait MemberLookup { * Will return a `Tooltip` if unsucessfull, otherwise a LinkToEntity or * LinkToExternal */ - def lookup(entity: Entity, packages: Map[String, Package], query: String): LinkTo = { - val notFound: LinkTo = Tooltip(query) + def lookup(entity: Entity, packages: Map[String, Package], query: String): Option[Entity] = { + val notFound: Option[Entity] = None val querys = query.split("\\.").toList /** Looks for the specified entity among `ent`'s members */ - def localLookup(ent: Entity with Members, searchStr: String): LinkTo = + def localLookup(ent: Entity with Members, searchStr: String): Option[Entity] = 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 */ - def downwardLookup(ent: Entity with Members, search: List[String]): LinkTo = + def downwardLookup(ent: Entity with Members, search: List[String]): Option[Entity] = search match { case Nil => notFound case x :: Nil => @@ -54,7 +53,7 @@ trait MemberLookup { /** Finds package with longest matching name, then does downwardLookup in * the package */ - def globalLookup: LinkTo = { + def globalLookup: Option[Entity] = { def longestMatch(list: List[String]): List[String] = if (list eq Nil) Nil else @@ -84,7 +83,13 @@ trait MemberLookup { entity: Entity, packages: Map[String, Package], title: Inline, - pos: Position, query: String - ): EntityLink = EntityLink(title, lookup(entity, packages, query)) + ): EntityLink = { + val link = + lookup(entity, packages, query) + .map(LinkToEntity) + .getOrElse(Tooltip(query)) + + EntityLink(title, link) + } } -- cgit v1.2.3