From 302126067d6b05b26c7f2fffe7fda5d058b32b33 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Tue, 3 Jan 2017 16:23:56 +0100 Subject: Add markdown parsing to dottydoc --- project/Build.scala | 2 ++ 1 file changed, 2 insertions(+) (limited to 'project') diff --git a/project/Build.scala b/project/Build.scala index 778492624..57a915c9c 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -185,6 +185,8 @@ object DottyBuild extends Build { libraryDependencies ++= Seq("org.scala-lang.modules" %% "scala-xml" % "1.0.1", "org.scala-lang.modules" %% "scala-partest" % "1.0.11" % "test", dottyOrganization % "dottydoc-client" % "0.1.0", + "com.vladsch.flexmark" % "flexmark" % "0.10.1", + "com.vladsch.flexmark" % "flexmark-ext-tables" % "0.10.1", "com.novocode" % "junit-interface" % "0.11" % "test", "com.github.spullara.mustache.java" % "compiler" % "0.9.3", "com.typesafe.sbt" % "sbt-interface" % sbtVersion.value), -- cgit v1.2.3 From 1dc446fc8973dce2da0bbb3c6eb97aa035d0d191 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Thu, 5 Jan 2017 17:15:02 +0100 Subject: Add initial page rendering using liquid and yaml front matter --- .../tools/dottydoc/core/ContextDottydoc.scala | 5 +- .../src/dotty/tools/dottydoc/staticsite/Page.scala | 50 ++++++++++++++++ doc-tool/test/YamlTest.scala | 69 ++++++++++++++++++++++ project/Build.scala | 2 + 4 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 doc-tool/src/dotty/tools/dottydoc/staticsite/Page.scala create mode 100644 doc-tool/test/YamlTest.scala (limited to 'project') diff --git a/doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala b/doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala index 963c72bc9..c2dd3fdef 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala @@ -8,7 +8,9 @@ import model.Package import com.vladsch.flexmark.parser.ParserEmulationFamily import com.vladsch.flexmark.parser.Parser import com.vladsch.flexmark.ext.tables.TablesExtension +import com.vladsch.flexmark.ext.front.matter.YamlFrontMatterExtension import com.vladsch.flexmark.util.options.{ DataHolder, MutableDataSet } +import java.util.{ Collections => JCollections } class ContextDottydoc extends ContextDocstrings { import scala.collection.mutable @@ -28,5 +30,6 @@ class ContextDottydoc extends ContextDocstrings { val markdownOptions: DataHolder = new MutableDataSet() .setFrom(ParserEmulationFamily.KRAMDOWN.getOptions) - .set(Parser.EXTENSIONS, java.util.Collections.singleton(TablesExtension.create())) + .set(Parser.EXTENSIONS, JCollections.singleton(TablesExtension.create())) + .set(Parser.EXTENSIONS, JCollections.singleton(YamlFrontMatterExtension.create())) } diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Page.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Page.scala new file mode 100644 index 000000000..7048109fd --- /dev/null +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Page.scala @@ -0,0 +1,50 @@ +package dotty.tools +package dottydoc +package staticsite + +import dotc.core.Contexts.Context +import dotty.tools.dottydoc.util.syntax._ + +import com.vladsch.flexmark.html.HtmlRenderer +import com.vladsch.flexmark.parser.Parser +import com.vladsch.flexmark.ext.front.matter.AbstractYamlFrontMatterVisitor +import liqp.{ Template => LiquidTemplate } + +class MarkdownPage(fileContents: => String, params: Map[String, AnyRef]) { + import scala.collection.JavaConverters._ + + def yaml(implicit ctx: Context): Map[String, String] = { + if (_yaml eq null) initFields() + _yaml + } + + def html(implicit ctx: Context): String = { + if (_html eq null) initFields() + _html + } + + private[this] var _yaml: Map[String, String] = _ + private[this] var _html: String = _ + private[this] def initFields()(implicit ctx: Context) = { + val template = LiquidTemplate.parse(fileContents) + val yamlCollector = new AbstractYamlFrontMatterVisitor() + val mdParser = Parser.builder(ctx.docbase.markdownOptions).build + + yamlCollector.visit(mdParser.parse(fileContents)) + + _yaml = yamlCollector + .getData().asScala + .mapValues(_.asScala.headOption.getOrElse("")) + .toMap + + // make accessible via "{{ page.title }}" in templates + val page = Map("page" -> _yaml.asJava) + val renderedTemplate = template.render((page ++ params).asJava) + + _html = HtmlRenderer + .builder(ctx.docbase.markdownOptions) + .escapeHtml(false) + .build() + .render(mdParser.parse(renderedTemplate)) + } +} diff --git a/doc-tool/test/YamlTest.scala b/doc-tool/test/YamlTest.scala new file mode 100644 index 000000000..2d633d12c --- /dev/null +++ b/doc-tool/test/YamlTest.scala @@ -0,0 +1,69 @@ +package dotty.tools +package dottydoc + +import org.junit.Test +import org.junit.Assert._ + +import staticsite.MarkdownPage + +class YamlTest extends DottyDocTest { + import scala.collection.JavaConverters._ + + @Test def has1Key = { + val page = new MarkdownPage( + """|--- + |key: + |--- + | + |great""".stripMargin, + Map.empty + ) + + assert( + page.yaml == Map("key" -> ""), + s"""incorrect yaml, expected "key:" without key in: ${page.yaml}""" + ) + + assertEquals("

great

\n", page.html) + } + + @Test def yamlPreservesLiquidTags = { + val page1 = new MarkdownPage( + """|--- + |key: + |--- + | + |{{ content }}""".stripMargin, + Map("content" -> "Hello, world!") + ) + + assert( + page1.yaml == Map("key" -> ""), + s"""incorrect yaml, expected "key:" without key in: ${page1.yaml}""" + ) + + assertEquals("

Hello, world!

\n", page1.html) + + val page2 = new MarkdownPage( + """|{{ content }}""".stripMargin, + Map("content" -> "hello") + ) + assert( + page2.yaml == Map(), + s"""incorrect yaml, expected "key:" without key in: ${page2.yaml}""" + ) + assertEquals("

hello

\n", page2.html) + + val page3 = new MarkdownPage( + """|{% if product.title == "Awesome Shoes" %} + |These shoes are awesome! + |{% endif %}""".stripMargin, + Map("product" -> Map("title" -> "Awesome Shoes").asJava) + ) + + assertEquals( + "

These shoes are awesome!

\n", + page3.html + ) + } +} diff --git a/project/Build.scala b/project/Build.scala index 57a915c9c..ba16ec38d 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -187,6 +187,8 @@ object DottyBuild extends Build { dottyOrganization % "dottydoc-client" % "0.1.0", "com.vladsch.flexmark" % "flexmark" % "0.10.1", "com.vladsch.flexmark" % "flexmark-ext-tables" % "0.10.1", + "com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % "0.10.3", + "nl.big-o" % "liqp" % "0.6.7", "com.novocode" % "junit-interface" % "0.11" % "test", "com.github.spullara.mustache.java" % "compiler" % "0.9.3", "com.typesafe.sbt" % "sbt-interface" % sbtVersion.value), -- cgit v1.2.3 From cbb9ae997825592e6d307d2feb89ba9e0a202820 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Fri, 6 Jan 2017 13:54:49 +0100 Subject: Add resource dir to dottydoc --- project/Build.scala | 2 ++ 1 file changed, 2 insertions(+) (limited to 'project') diff --git a/project/Build.scala b/project/Build.scala index ba16ec38d..e27ec350c 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -373,6 +373,8 @@ object DottyBuild extends Build { // project, for sbt integration // FIXME: note part of dottyCompilerSettings because the doc-tool does not // compile with dotty + unmanagedResourceDirectories in Compile := Seq((resourceDirectory in Compile).value), + unmanagedResourceDirectories in Compile += baseDirectory.value / ".." / "doc-tool" / "resources", unmanagedSourceDirectories in Compile := Seq((scalaSource in Compile).value), unmanagedSourceDirectories in Compile += baseDirectory.value / ".." / "doc-tool" / "src", unmanagedSourceDirectories in Test := Seq((scalaSource in Test).value), -- cgit v1.2.3 From ae89a7a1e067c3e7dde7d5fc8a8a016689f0b9e3 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Fri, 13 Jan 2017 14:23:57 +0100 Subject: fix extensions not getting loaded properly --- doc-tool/resources/css/api-page.css | 4 ++++ .../src/dotty/tools/dottydoc/staticsite/Site.scala | 18 ++++++++++++++---- project/Build.scala | 6 +++++- 3 files changed, 23 insertions(+), 5 deletions(-) (limited to 'project') diff --git a/doc-tool/resources/css/api-page.css b/doc-tool/resources/css/api-page.css index 47f88ed6c..e2927f0d4 100644 --- a/doc-tool/resources/css/api-page.css +++ b/doc-tool/resources/css/api-page.css @@ -19,6 +19,10 @@ div#entity-title > span#entity-kind { font-weight: 100; } +div#entity-body table > tbody > tr > td { + padding: 10px; +} + div.entity-section { background-color: #fff; border-radius: 4px; diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala index d190eea88..a2dad5315 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala @@ -5,14 +5,18 @@ package staticsite import java.nio.file.{ Files, FileSystems } import java.nio.file.StandardCopyOption.REPLACE_EXISTING import java.io.{ File => JFile } -import java.util.{ List => JList, Map => JMap, Collections => JCollections } +import java.util.{ List => JList, Map => JMap, Arrays } import java.nio.file.Path import java.io.ByteArrayInputStream import java.nio.charset.StandardCharsets import com.vladsch.flexmark.parser.ParserEmulationFamily import com.vladsch.flexmark.parser.Parser -import com.vladsch.flexmark.ext.tables.TablesExtension +import com.vladsch.flexmark.ext.gfm.tables.TablesExtension +import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension +import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension +import com.vladsch.flexmark.ext.emoji.EmojiExtension +import com.vladsch.flexmark.ext.autolink.AutolinkExtension import com.vladsch.flexmark.ext.front.matter.YamlFrontMatterExtension import com.vladsch.flexmark.util.options.{ DataHolder, MutableDataSet } @@ -340,6 +344,12 @@ object Site { val markdownOptions: DataHolder = new MutableDataSet() .setFrom(ParserEmulationFamily.KRAMDOWN.getOptions) - .set(Parser.EXTENSIONS, JCollections.singleton(TablesExtension.create())) - .set(Parser.EXTENSIONS, JCollections.singleton(YamlFrontMatterExtension.create())) + .set(Parser.EXTENSIONS, Arrays.asList( + TablesExtension.create(), + TaskListExtension.create(), + AutolinkExtension.create(), + EmojiExtension.create(), + YamlFrontMatterExtension.create(), + StrikethroughExtension.create() + )) } diff --git a/project/Build.scala b/project/Build.scala index e27ec350c..025f5c2dd 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -186,7 +186,11 @@ object DottyBuild extends Build { "org.scala-lang.modules" %% "scala-partest" % "1.0.11" % "test", dottyOrganization % "dottydoc-client" % "0.1.0", "com.vladsch.flexmark" % "flexmark" % "0.10.1", - "com.vladsch.flexmark" % "flexmark-ext-tables" % "0.10.1", + "com.vladsch.flexmark" % "flexmark-ext-gfm-tasklist" % "0.10.1", + "com.vladsch.flexmark" % "flexmark-ext-gfm-tables" % "0.10.1", + "com.vladsch.flexmark" % "flexmark-ext-autolink" % "0.10.1", + "com.vladsch.flexmark" % "flexmark-ext-emoji" % "0.10.1", + "com.vladsch.flexmark" % "flexmark-ext-gfm-strikethrough" % "0.11.1", "com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % "0.10.3", "nl.big-o" % "liqp" % "0.6.7", "com.novocode" % "junit-interface" % "0.11" % "test", -- cgit v1.2.3 From 6f6dc9767badd4bcacd8f00ef0ed467bcabc6296 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Mon, 16 Jan 2017 14:05:15 +0100 Subject: Re-implement template expansion of references as filter The original implementation used the template engine to recursively expand references. This was very error-prone and with no typesafety and proper stack traces it was very hard to diagnose. As such, these two expansions (links and references) have been re-implemented as filters. --- doc-tool/resources/_includes/link.html | 6 -- doc-tool/resources/_includes/reference.html | 77 -------------- doc-tool/resources/_layouts/api-page.html | 11 +- doc-tool/src/dotty/tools/dottydoc/model/java.scala | 33 ++++-- .../dotty/tools/dottydoc/model/references.scala | 8 ++ .../tools/dottydoc/staticsite/LiquidTemplate.scala | 12 +-- .../src/dotty/tools/dottydoc/staticsite/Site.scala | 8 +- .../dotty/tools/dottydoc/staticsite/filters.scala | 116 +++++++++++++++++++++ project/Build.scala | 12 +-- 9 files changed, 166 insertions(+), 117 deletions(-) delete mode 100644 doc-tool/resources/_includes/link.html delete mode 100644 doc-tool/resources/_includes/reference.html create mode 100644 doc-tool/src/dotty/tools/dottydoc/staticsite/filters.scala (limited to 'project') diff --git a/doc-tool/resources/_includes/link.html b/doc-tool/resources/_includes/link.html deleted file mode 100644 index 621894eaf..000000000 --- a/doc-tool/resources/_includes/link.html +++ /dev/null @@ -1,6 +0,0 @@ -{% case tpeLink.kind %} -{% when 'NoLink' %} - {{ tpeLink.title }} -{% else %} - {{ tpeLink.title }} -{% endcase %} diff --git a/doc-tool/resources/_includes/reference.html b/doc-tool/resources/_includes/reference.html deleted file mode 100644 index eb741c02c..000000000 --- a/doc-tool/resources/_includes/reference.html +++ /dev/null @@ -1,77 +0,0 @@ -{% case reference.kind %} -{% when 'TypeReference' %} - - {% assign tpeLink = reference.tpeLink %} - {% include 'link' %} - {% if reference.paramLinks.size > 0 %} - [ - {% for reference in reference.paramLinks %} - {% include 'reference' %} - {% if forloop.last != true %} - , - {% endif %} - {% endfor %} - ] - {% endif %} - -{% when 'FunctionReference' %} - - {% assign originalLink = reference %} - {% case reference.args.size %} - {% when 0 %} - () - {% when 1 %} - {% for reference in reference.args %} - {% include 'reference' %} - {% endfor %} - {% else %} - {% for reference in reference.args %} - {% if forloop.first %} - ( - {% endif %} - {% include 'reference' %} - {% if forloop.last != true %} - , - {% else %} - ) - {% endif %} - {% endfor %} - {% endcase %} - => - {% assign reference = originalLink.returnValue %} - {% include 'reference' %} - -{% when 'TupleReference' %} - - {% for reference in reference.args %} - {% if forloop.first %}({% endif %} - {% include 'reference' %} - {% if forloop.last %} - ) - {% else %} - , - {% endif %} - {% endfor %} - -{% when 'BoundsReference' %} - - {% assign oldRef = reference %} - {% assign reference = oldRef.low %} - {% include 'reference' %} - <: - {% assign reference = oldRef.hi %} - {% include 'reference' %} - -{% when 'ConstantReference' %} - {{ reference.title }} - -{% else %} - - {% assign original= reference %} - {% assign reference = original.left %} - {% include 'reference' %} - {% if original.kind == "OrTypeReference" %}|{% else %}&{% endif %} - {% assign reference = original.right %} - {% include 'reference' %} - -{% endcase %} diff --git a/doc-tool/resources/_layouts/api-page.html b/doc-tool/resources/_layouts/api-page.html index 292c334dc..ed65c0651 100644 --- a/doc-tool/resources/_layouts/api-page.html +++ b/doc-tool/resources/_layouts/api-page.html @@ -48,12 +48,13 @@ extraCSS: {% if plist.isImplicit %} implicit {% endif %} - {% for ref in plist.list %} - {{ ref.title }}:{% if ref.isByName %} =>{% endif %} - {% assign reference = ref.ref %} - {% include "reference" %} + {% for namedRef in plist.list %} + + {{ namedRef.title }}:{% if namedRef.isByName %} =>{% endif %} + + {{ namedRef.ref | renderRef }} {% if forloop.last != true %} - , + , {% endif %} {% endfor %} ) diff --git a/doc-tool/src/dotty/tools/dottydoc/model/java.scala b/doc-tool/src/dotty/tools/dottydoc/model/java.scala index c20206ced..c46414061 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/java.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/java.scala @@ -151,36 +151,42 @@ object java { "kind" -> "TypeReference", "title" -> title, "tpeLink" -> tpeLink.asJava, - "paramLinks" -> paramLinks.map(_.asJava).asJava + "paramLinks" -> paramLinks.map(_.asJava).asJava, + "scala" -> ref ).asJava case OrTypeReference(left, right) => Map( "kind" -> "OrTypeReference", "left" -> left.asJava, - "right" -> right.asJava + "right" -> right.asJava, + "scala" -> ref ).asJava case AndTypeReference(left, right) => Map( "kind" -> "AndTypeReference", "left" -> left.asJava, - "right" -> right.asJava + "right" -> right.asJava, + "scala" -> ref ).asJava case FunctionReference(args, returnValue) => Map( "kind" -> "FunctionReference", "args" -> args.map(_.asJava).asJava, - "returnValue" -> returnValue.asJava + "returnValue" -> returnValue.asJava, + "scala" -> ref ).asJava case TupleReference(args) => Map( "kind" -> "TupleReference", - "args" -> args.map(_.asJava).asJava + "args" -> args.map(_.asJava).asJava, + "scala" -> ref ).asJava case BoundsReference(low, high) => Map( "kind" -> "BoundsReference", "low" -> low.asJava, - "hight" -> high.asJava + "hight" -> high.asJava, + "scala" -> ref ).asJava case NamedReference(title, ref, isByName, isRepeated) => Map( @@ -188,12 +194,14 @@ object java { "title" -> title, "ref" -> ref.asJava, "isByName" -> isByName, - "isRepeated" -> isRepeated + "isRepeated" -> isRepeated, + "scala" -> ref ).asJava case ConstantReference(title) => Map( "kind" -> "ConstantReference", - "title" -> title + "title" -> title, + "scala" -> ref ).asJava } } @@ -203,19 +211,22 @@ object java { case UnsetLink(title, query) => Map( "kind" -> "UnsetLink", "title" -> title, - "query" -> query + "query" -> query, + "scala" -> link ).asJava case MaterializedLink(title, target) => Map( "kind" -> "MaterializedLink", "title" -> title, - "target" -> target + "target" -> target, + "scala" -> link ).asJava case NoLink(title, target) => Map( "kind" -> "NoLink", "title" -> title, - "target" -> target + "target" -> target, + "scala" -> link ).asJava } } diff --git a/doc-tool/src/dotty/tools/dottydoc/model/references.scala b/doc-tool/src/dotty/tools/dottydoc/model/references.scala index a28148fa7..766b2a340 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/references.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/references.scala @@ -17,4 +17,12 @@ object references { final case class UnsetLink(title: String, query: String) extends MaterializableLink final case class MaterializedLink(title: String, target: String) extends MaterializableLink final case class NoLink(title: String, target: String) extends MaterializableLink + + object AndOrTypeReference { + def unapply(ref: Reference): Option[(Reference, String, Reference)] = ref match { + case OrTypeReference(left, right) => Some((left, "|", right)) + case AndTypeReference(left, right) => Some((left, "&", right)) + case _ => None + } + } } diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/LiquidTemplate.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/LiquidTemplate.scala index 99ee54b74..a92e5d48e 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/LiquidTemplate.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/LiquidTemplate.scala @@ -12,14 +12,12 @@ case class LiquidTemplate(contents: String) extends ResourceFinder { import liqp.filters.Filter import liqp.parser.Flavor.JEKYLL import java.util.{ HashMap, Map => JMap } + import filters._ - Filter.registerFilter(new Filter("reverse") { - override def apply(value: Any, params: AnyRef*): AnyRef = { - val array = super.asArray(value) - if (array.length == 0) null - else array.reverse - } - }) + /** 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] = diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala index 03e78024c..d314f0eab 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala @@ -10,7 +10,7 @@ import java.nio.file.Path import java.io.ByteArrayInputStream import java.nio.charset.StandardCharsets -import com.vladsch.flexmark.parser.ParserEmulationFamily +import com.vladsch.flexmark.parser.ParserEmulationProfile import com.vladsch.flexmark.parser.Parser import com.vladsch.flexmark.ext.gfm.tables.TablesExtension import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension @@ -311,9 +311,7 @@ case class Site(val root: JFile, val documentation: Map[String, Package]) extend val defaultIncludes: Map[String, String] = Map( "header.html" -> "/_includes/header.html", "scala-logo.html" -> "/_includes/scala-logo.html", - "toc.html" -> "/_includes/toc.html", - "reference.html" -> "/_includes/reference.html", - "link.html" -> "/_includes/link.html" + "toc.html" -> "/_includes/toc.html" ).mapValues(getResource) @@ -345,7 +343,7 @@ case class Site(val root: JFile, val documentation: Map[String, Package]) extend object Site { val markdownOptions: DataHolder = new MutableDataSet() - .setFrom(ParserEmulationFamily.KRAMDOWN.getOptions) + .setFrom(ParserEmulationProfile.KRAMDOWN.getOptions) .set(Parser.EXTENSIONS, Arrays.asList( TablesExtension.create(), TaskListExtension.create(), diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/filters.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/filters.scala new file mode 100644 index 000000000..bb6f314dc --- /dev/null +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/filters.scala @@ -0,0 +1,116 @@ +package dotty.tools +package dottydoc +package staticsite + +import model.references._ +import java.util.{ Map => JMap } + +import liqp.filters.Filter + +/** Custom liquid template filters */ +object filters { + + /** Used to reverse arrays: + * + * ```html + * {% assign array = "1,2,3,4,5" | split: "," %} + * {{ array | reverse }} + * ``` + */ + final class Reverse extends Filter("reverse") { + override def apply(value: Any, params: AnyRef*): AnyRef = { + val array = super.asArray(value) + if (array.length == 0) null + 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 => + renderReference(value.get("scala").asInstanceOf[Reference]) + 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/project/Build.scala b/project/Build.scala index 025f5c2dd..dd492447a 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -185,13 +185,13 @@ object DottyBuild extends Build { libraryDependencies ++= Seq("org.scala-lang.modules" %% "scala-xml" % "1.0.1", "org.scala-lang.modules" %% "scala-partest" % "1.0.11" % "test", dottyOrganization % "dottydoc-client" % "0.1.0", - "com.vladsch.flexmark" % "flexmark" % "0.10.1", - "com.vladsch.flexmark" % "flexmark-ext-gfm-tasklist" % "0.10.1", - "com.vladsch.flexmark" % "flexmark-ext-gfm-tables" % "0.10.1", - "com.vladsch.flexmark" % "flexmark-ext-autolink" % "0.10.1", - "com.vladsch.flexmark" % "flexmark-ext-emoji" % "0.10.1", + "com.vladsch.flexmark" % "flexmark" % "0.11.1", + "com.vladsch.flexmark" % "flexmark-ext-gfm-tasklist" % "0.11.1", + "com.vladsch.flexmark" % "flexmark-ext-gfm-tables" % "0.11.1", + "com.vladsch.flexmark" % "flexmark-ext-autolink" % "0.11.1", + "com.vladsch.flexmark" % "flexmark-ext-emoji" % "0.11.1", "com.vladsch.flexmark" % "flexmark-ext-gfm-strikethrough" % "0.11.1", - "com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % "0.10.3", + "com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % "0.11.1", "nl.big-o" % "liqp" % "0.6.7", "com.novocode" % "junit-interface" % "0.11" % "test", "com.github.spullara.mustache.java" % "compiler" % "0.9.3", -- cgit v1.2.3 From 637c888b8fad660464fc1b35d40279c3482cab65 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Tue, 17 Jan 2017 16:20:17 +0100 Subject: Add `genDocs` command to sbt in order to generate docs --- doc-tool/src/dotty/tools/dottydoc/DocDriver.scala | 6 ++--- .../tools/dottydoc/core/MiniPhaseTransform.scala | 2 +- .../tools/dottydoc/core/SortMembersPhase.scala | 10 ++++++++- .../dottydoc/model/comment/BodyEntities.scala | 4 ++-- .../tools/dottydoc/model/comment/HtmlParsers.scala | 8 +++---- .../tools/dottydoc/model/comment/WikiParser.scala | 26 +++++++++++----------- .../src/dotty/tools/dottydoc/staticsite/Site.scala | 4 ++-- project/Build.scala | 18 +++++++++++++++ 8 files changed, 51 insertions(+), 27 deletions(-) (limited to 'project') diff --git a/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala b/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala index 0225b3c5e..e5a2cc266 100644 --- a/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala +++ b/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala @@ -54,7 +54,7 @@ class DocDriver extends Driver { override def main(args: Array[String]): Unit = { implicit val (filesToDocument, ctx) = setup(args, initCtx.fresh) - doCompile(newCompiler(ctx), filesToDocument)(ctx) + val reporter = doCompile(newCompiler(ctx), filesToDocument)(ctx) val docs = ctx.docbase.packages val siteRoot = new java.io.File(ctx.settings.siteRoot.value) @@ -68,9 +68,7 @@ class DocDriver extends Driver { .generateHtmlFiles() .generateBlog() - // FIXME: liqp templates are compiled by threadpools, for some reason it - // is not shutting down :-( - System.exit(0) + System.exit(if (reporter.hasErrors) 1 else 0) } } } diff --git a/doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala b/doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala index d87cdf098..b6fbe0238 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala @@ -204,7 +204,7 @@ object transform { trait DocMiniPhase { phase => private def identity[E]: PartialFunction[E, E] = { - case id => id + case id: E @unchecked => id } def transformPackage(implicit ctx: Context): PartialFunction[Package, Package] = identity diff --git a/doc-tool/src/dotty/tools/dottydoc/core/SortMembersPhase.scala b/doc-tool/src/dotty/tools/dottydoc/core/SortMembersPhase.scala index 29898b140..a281558d4 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/SortMembersPhase.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/SortMembersPhase.scala @@ -10,9 +10,17 @@ import model.internal._ /** This DocMiniPhase sorts the members of all classes, traits, objects and packages */ class SortMembers extends DocMiniPhase { + private implicit val EntityOrdering: Ordering[Entity] = new Ordering[Entity] { + def compare(x: Entity, y: Entity): Int = { + val nameComp = x.name.compareTo(y.name) + if (nameComp == 0) x.kind.compareTo(y.kind) + else nameComp + } + } + private def sort(xs: List[Entity]): List[Entity] = { def sortOrNil(xs: Option[List[Entity]]*) = - xs.map(_.getOrElse(Nil)).reduceLeft(_ ++ _).sortBy(_.name) + xs.map(_.getOrElse(Nil)).reduceLeft(_ ++ _).sorted val map = xs.groupBy(_.kind) diff --git a/doc-tool/src/dotty/tools/dottydoc/model/comment/BodyEntities.scala b/doc-tool/src/dotty/tools/dottydoc/model/comment/BodyEntities.scala index 29fe48de3..1d49a4f4f 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/comment/BodyEntities.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/comment/BodyEntities.scala @@ -32,8 +32,8 @@ final case class Body(blocks: Seq[Block]) { } (blocks flatMap summaryInBlock).toList match { case Nil => None - case inline :: Nil => Some(Body(Seq(Paragraph(inline)))) - case inlines => Some(Body(Seq(Paragraph(Chain(inlines))))) + case inl :: Nil => Some(Body(Seq(Paragraph(inl)))) + case inls => Some(Body(Seq(Paragraph(Chain(inls))))) } } } 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 a44c2fc1d..475157dce 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/comment/HtmlParsers.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/comment/HtmlParsers.scala @@ -104,8 +104,8 @@ object HtmlParsers { item match { case OrderedList(_, _) | UnorderedList(_) => // html requires sub ULs to be put into the last LI list + s"
  • ${blockToHtml(item)}
  • " - case Paragraph(inline) => - list + s"
  • ${inlineToHtml(inline)}
  • " // LIs are blocks, no need to use Ps + case Paragraph(inl) => + list + s"
  • ${inlineToHtml(inl)}
  • " // LIs are blocks, no need to use Ps case block => list + s"
  • ${blockToHtml(block)}
  • " } @@ -116,12 +116,12 @@ object HtmlParsers { } case class InlineToHtml(origin: Entity) { - def apply(inline: Inline) = toHtml(inline) + def apply(inl: Inline) = toHtml(inl) def relativePath(target: Entity) = util.traversing.relativePath(origin, target) - def toHtml(inline: Inline): String = inline match { + def toHtml(inl: Inline): String = inl match { case Chain(items) => (items map toHtml).mkString case Italic(in) => s"${toHtml(in)}" case Bold(in) => s"${toHtml(in)}" 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 92174f74f..13d74d4b3 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/comment/WikiParser.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/comment/WikiParser.scala @@ -82,7 +82,7 @@ private[comment] final class WikiParser( else { jumpWhitespace() jump(style) - val p = Paragraph(inline(isInlineEnd = false)) + val p = Paragraph(getInline(isInlineEnd = false)) blockEnded("end of list line ") Some(p) } @@ -121,7 +121,7 @@ private[comment] final class WikiParser( def title(): Block = { jumpWhitespace() val inLevel = repeatJump('=') - val text = inline(check("=" * inLevel)) + val text = getInline(check("=" * inLevel)) val outLevel = repeatJump('=', inLevel) if (inLevel != outLevel) reportError(pos, "unbalanced or unclosed heading") @@ -141,11 +141,11 @@ private[comment] final class WikiParser( def para(): Block = { val p = if (summaryParsed) - Paragraph(inline(isInlineEnd = false)) + Paragraph(getInline(isInlineEnd = false)) else { val s = summary() val r = - if (checkParaEnded()) List(s) else List(s, inline(isInlineEnd = false)) + if (checkParaEnded()) List(s) else List(s, getInline(isInlineEnd = false)) summaryParsed = true Paragraph(Chain(r)) } @@ -193,7 +193,7 @@ private[comment] final class WikiParser( list mkString "" } - def inline(isInlineEnd: => Boolean): Inline = { + def getInline(isInlineEnd: => Boolean): Inline = { def inline0(): Inline = { if (char == safeTagMarker) { @@ -264,35 +264,35 @@ private[comment] final class WikiParser( def bold(): Inline = { jump("'''") - val i = inline(check("'''")) + val i = getInline(check("'''")) jump("'''") Bold(i) } def italic(): Inline = { jump("''") - val i = inline(check("''")) + val i = getInline(check("''")) jump("''") Italic(i) } def monospace(): Inline = { jump("`") - val i = inline(check("`")) + val i = getInline(check("`")) jump("`") Monospace(i) } def underline(): Inline = { jump("__") - val i = inline(check("__")) + val i = getInline(check("__")) jump("__") Underline(i) } def superscript(): Inline = { jump("^") - val i = inline(check("^")) + val i = getInline(check("^")) if (jump("^")) { Superscript(i) } else { @@ -302,13 +302,13 @@ private[comment] final class WikiParser( def subscript(): Inline = { jump(",,") - val i = inline(check(",,")) + val i = getInline(check(",,")) jump(",,") Subscript(i) } def summary(): Inline = { - val i = inline(checkSentenceEnded()) + val i = getInline(checkSentenceEnded()) Summary( if (jump(".")) Chain(List(i, Text("."))) @@ -326,7 +326,7 @@ private[comment] final class WikiParser( val title = if (!check(stop)) Some({ jumpWhitespaceOrNewLine() - inline(check(stop)) + getInline(check(stop)) }) else None jump(stop) diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala index e991148d6..6cdff2f22 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala @@ -257,9 +257,9 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma root .listFiles .find(dir => dir.getName == "blog" && dir.isDirectory) - .map(_.listFiles).getOrElse(Array.empty) + .map(_.listFiles).getOrElse(Array.empty[JFile]) //FIXME: remove [JFile] once #1907 is fixed .find(dir => dir.getName == "_posts" && dir.isDirectory) - .map(_.listFiles).getOrElse(Array.empty) + .map(_.listFiles).getOrElse(Array.empty[JFile]) //FIXME: remove [JFile] once #1907 is fixed .flatMap(collectPosts) } diff --git a/project/Build.scala b/project/Build.scala index dd492447a..f7e8e4754 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -52,6 +52,9 @@ object DottyBuild extends Build { lazy val dotr = inputKey[Unit]("run compiled binary using the correct classpath, or the user supplied classpath") + // Compiles the documentation and static site + lazy val genDocs = inputKey[Unit]("run dottydoc to generate static documentation site") + override def settings: Seq[Setting[_]] = { super.settings ++ Seq( scalaVersion in Global := scalacVersion, @@ -212,6 +215,21 @@ object DottyBuild extends Build { ) }.evaluated, + genDocs := Def.inputTaskDyn { + val dottyLib = packageAll.value("dotty-library") + val dottyInterfaces = packageAll.value("dotty-interfaces") + val otherDeps = (dependencyClasspath in Compile).value.map(_.data).mkString(":") + val sources = (managedSources in (Compile, compile)).value ++ (unmanagedSources in (Compile, compile)).value + val args: Seq[String] = Seq( + "-siteroot", "docs", + "-project", "Dotty", + "-classpath", s"$dottyLib:$dottyInterfaces:$otherDeps" + ) + (runMain in Compile).toTask( + s""" dotty.tools.dottydoc.Main ${args.mkString(" ")} ${sources.mkString(" ")}""" + ) + }.evaluated, + // Override run to be able to run compiled classfiles dotr := { val args: Seq[String] = spaceDelimited("").parsed -- cgit v1.2.3 From 7b2c84b51850a4e64107a99f9780d0ee578a1c4a Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Mon, 23 Jan 2017 16:04:20 +0100 Subject: Generalize table of contents for dottydoc --- doc-tool/resources/_includes/toc.html | 52 ++-------------------- doc-tool/resources/css/dottydoc.css | 9 ++-- .../tools/dottydoc/staticsite/DefaultParams.scala | 41 ++++++++++++++++- .../tools/dottydoc/staticsite/LiquidTemplate.scala | 1 + .../src/dotty/tools/dottydoc/staticsite/Site.scala | 12 ++++- .../src/dotty/tools/dottydoc/staticsite/Yaml.scala | 23 ++++++++++ .../src/dotty/tools/dottydoc/staticsite/tags.scala | 37 +++++++++++++++ docs/sidebar.yml | 47 +++++++++++++++++++ project/Build.scala | 1 + 9 files changed, 169 insertions(+), 54 deletions(-) create mode 100644 doc-tool/src/dotty/tools/dottydoc/staticsite/Yaml.scala create mode 100644 docs/sidebar.yml (limited to 'project') diff --git a/doc-tool/resources/_includes/toc.html b/doc-tool/resources/_includes/toc.html index 0ff3f9586..15952ef78 100644 --- a/doc-tool/resources/_includes/toc.html +++ b/doc-tool/resources/_includes/toc.html @@ -1,55 +1,11 @@ -{% assign parent = page.path | first %} - - diff --git a/doc-tool/resources/css/dottydoc.css b/doc-tool/resources/css/dottydoc.css index bb0d6506b..aa197de07 100644 --- a/doc-tool/resources/css/dottydoc.css +++ b/doc-tool/resources/css/dottydoc.css @@ -85,7 +85,7 @@ ul.toc > li > a#home-button svg g#logo-background { fill: rgba(202, 68, 94, 0.45); } -ul.toc > li > a.toggle-children { +ul.toc > li > a { width: 100%; user-select: none; } @@ -182,13 +182,16 @@ ul.index-entities > li.index-title > span { padding: 0 24px; } +ul.index-entities > li.index-title:hover { + background-color: transparent; +} + li.index-entity > a:focus { text-decoration: none; } ul.index-entities > li:hover, -ul.toc > li.toc-title:hover, -ul.toc > li > a.toggle-children:hover { +ul.toc > li > a:hover { background-color: rgba(0, 0, 0, 0.2); } diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala index d64ebcd90..5bed79869 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala @@ -2,17 +2,19 @@ package dotty.tools package dottydoc package staticsite -import java.util.{ List => JList } import model.{ Entity, NonEntity } +import java.util.{ HashMap, List => JList, Map => JMap } +import scala.collection.JavaConverters._ + case class DefaultParams( docs: JList[_], page: PageInfo, site: SiteInfo, + sidebar: Sidebar, entity: Entity = NonEntity ) { import model.java._ - import scala.collection.JavaConverters._ def toMap: Map[String, AnyRef] = Map( "docs" -> docs, @@ -29,6 +31,8 @@ case class DefaultParams( "project" -> site.projectTitle ).asJava, + "sidebar" -> sidebar.titles.asJava, + "entity" -> entity.asJava() ) @@ -48,3 +52,36 @@ case class PageInfo(url: String, date: String = "") { } case class SiteInfo(baseurl: String, projectTitle: String, posts: Array[BlogPost]) + +case class Sidebar(titles: List[Title]) + +object Sidebar { + def apply(map: HashMap[String, AnyRef]): Option[Sidebar] = Option(map.get("sidebar")).map { + case list: JList[JMap[String, AnyRef]] @unchecked if !list.isEmpty => + new Sidebar(list.asScala.map(Title.apply).flatMap(x => x).toList) + case _ => Sidebar.empty + } + + def empty: Sidebar = Sidebar(Nil) +} + +case class Title(title: String, url: Option[String], subsection: List[Title]) + +object Title { + def apply(map: JMap[String, AnyRef]): Option[Title] = { + val title = Option(map.get("title")).collect { + case s: String => s + } + val url = Option(map.get("url")).collect { + case s: String => s + } + val subsection = Option(map.get("subsection")).collect { + case xs: JList[JMap[String, AnyRef]] @unchecked => + xs.asScala.map(Title.apply).toList.flatMap(x => x) + }.getOrElse(Nil) + + title.map { + case title: String => Title(title, url, subsection) + } + } +} diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/LiquidTemplate.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/LiquidTemplate.scala index 87209b47a..ef7a59f1c 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/LiquidTemplate.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/LiquidTemplate.scala @@ -28,5 +28,6 @@ case class LiquidTemplate(contents: String) extends ResourceFinder { Template.parse(contents, JEKYLL) .`with`(ResourceInclude(params, includes)) .`with`(RenderReference(params)) + .`with`(RenderTitle(params)) .render(toJavaMap(params)) } diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala index d522c597c..3fb5dad24 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala @@ -68,6 +68,16 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma _blogposts } + + val sidebar: Sidebar = + root + .listFiles + .find(_.getName == "sidebar.yml") + .map("---\n" + Source.fromFile(_).mkString + "\n---") + .map(Yaml.apply) + .flatMap(Sidebar.apply) + .getOrElse(Sidebar.empty) + protected lazy val blogInfo: Array[BlogPost] = blogposts .map { file => @@ -122,7 +132,7 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma "../" * (assetLen - rootLen - 1 + additionalDepth) + "." } - DefaultParams(docs, PageInfo(pathFromRoot), SiteInfo(baseUrl, projectTitle, Array())) + DefaultParams(docs, PageInfo(pathFromRoot), SiteInfo(baseUrl, projectTitle, Array()), sidebar) } private def createOutput(outDir: JFile)(op: => Unit): this.type = { diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Yaml.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Yaml.scala new file mode 100644 index 000000000..07bc27562 --- /dev/null +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Yaml.scala @@ -0,0 +1,23 @@ +package dotty.tools +package dottydoc +package staticsite + +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.core.`type`.TypeReference + +object Yaml { + import scala.collection.JavaConverters._ + import java.util.HashMap + import java.io.ByteArrayInputStream + + def apply(input: String): HashMap[String, AnyRef] = { + val is = new ByteArrayInputStream(input.getBytes("UTF-8")) + val mapper = new ObjectMapper(new YAMLFactory()) + + val typeRef: TypeReference[HashMap[String, AnyRef]] = + new TypeReference[HashMap[String, AnyRef]] {} + + mapper.readValue(is, typeRef) + } +} diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/tags.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/tags.scala index 868e28bce..fe6a05bbc 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/tags.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/tags.scala @@ -131,4 +131,41 @@ object tags { } } } + + /** Can be used to render the `sidebar.yml` entries, represented here as + * `Title`. + * + * ```html + * {% renderTitle title, parent %} + * ``` + * + * The rendering currently works on depths up to 2. This means that each + * title can have a subsection with its own titles. + */ + case class RenderTitle(params: Map[String, AnyRef]) extends Tag("renderTitle") with ParamConverter { + private def renderTitle(t: Title, parent: String): String = { + if (!t.url.isDefined && t.subsection.nonEmpty) { + val onclickFunction = + s"""(function(){var child=document.getElementById("${t.title}");child.classList.toggle("show");child.classList.toggle("hide");})();""" + s"""|${t.title} + |
      + | ${t.subsection.map(renderTitle(_, parent)).mkString("
    • ", "
    • ", "
    • ")} + |
    """.stripMargin + } + else if (t.url.isDefined) { + val url = t.url.get + s"""${t.title}""" + } + else /*if (t.subsection.nonEmpty)*/ { + /*dottydoc.*/println(s"url was defined for subsection with title: ${t.title}, remove url to get toggleable entries") + t.title + } + } + + override def render(ctx: TemplateContext, nodes: LNode*): AnyRef = + (nodes(0).render(ctx), nodes(1).render(ctx)) match { + case (t: Title, parent: String) => renderTitle(t, parent) + case _ => null + } + } } diff --git a/docs/sidebar.yml b/docs/sidebar.yml new file mode 100644 index 000000000..6353b3c90 --- /dev/null +++ b/docs/sidebar.yml @@ -0,0 +1,47 @@ +sidebar: + - title: Blog + url: blog/index.html + - title: Docs + url: docs/index.html + - title: Usage + subsection: + - title: cbt-projects + url: docs/usage/cbt-projects.html + - title: sbt-projects + url: docs/usage/sbt-projects.html + - title: Migrating + url: docs/usage/migrating.html + - title: Contributing + subsection: + - title: Eclipse + url: docs/contributing/eclipse.html + - title: Getting Started + url: docs/contributing/getting-started.html + - title: IntelliJ IDEA + url: docs/contributing/intellij-idea.html + - title: Workflow + url: docs/contributing/workflow.html + - title: Internals + subsection: + - title: Backend + url: docs/internals/backend.html + - title: Benchmarks + url: docs/internals/benchmarks.html + - title: Classpaths + url: docs/internals/classpaths.html + - title: Core Data Structrues + url: docs/internals/core-data-structures.html + - title: Contexts + url: docs/internals/contexts.html + - title: Dotc vs Scalac + url: docs/internals/dotc-scalac.html + - title: Higher-Kinded Types + url: docs/internals/higher-kinded-v2.html + - title: Overall Structure + url: docs/internals/overall-structure.html + - title: Periods + url: docs/internals/periods.html + - title: Syntax + url: docs/internals/syntax.html + - title: Type System + url: docs/internals/type-system.html diff --git a/project/Build.scala b/project/Build.scala index f7e8e4754..0abdc99be 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -195,6 +195,7 @@ object DottyBuild extends Build { "com.vladsch.flexmark" % "flexmark-ext-emoji" % "0.11.1", "com.vladsch.flexmark" % "flexmark-ext-gfm-strikethrough" % "0.11.1", "com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % "0.11.1", + "com.fasterxml.jackson.dataformat" % "jackson-dataformat-yaml" % "2.8.6", "nl.big-o" % "liqp" % "0.6.7", "com.novocode" % "junit-interface" % "0.11" % "test", "com.github.spullara.mustache.java" % "compiler" % "0.9.3", -- cgit v1.2.3 From 866e364dde76aa5df42548bf72d2f5c4d200535b Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Tue, 24 Jan 2017 17:35:53 +0100 Subject: Document dottydoc capabilities, add anchored headers --- doc-tool/resources/_layouts/api-page.html | 2 +- doc-tool/resources/_layouts/blog-page.html | 28 +++ doc-tool/resources/_layouts/blog.html | 28 --- doc-tool/resources/_layouts/doc-page.html | 2 +- doc-tool/resources/_layouts/doc.html | 49 ---- doc-tool/resources/_layouts/sidebar.html | 49 ++++ doc-tool/resources/css/dottydoc.css | 51 +++- .../dotty/tools/dottydoc/staticsite/BlogPost.scala | 11 +- .../src/dotty/tools/dottydoc/staticsite/Site.scala | 6 +- .../tools/dottydoc/staticsite/SiteTests.scala | 2 +- docs/blog/index.html | 2 +- docs/docs/usage/dottydoc.md | 260 +++++++++++++++++++++ docs/sidebar.yml | 2 + project/Build.scala | 1 + 14 files changed, 406 insertions(+), 87 deletions(-) create mode 100644 doc-tool/resources/_layouts/blog-page.html delete mode 100644 doc-tool/resources/_layouts/blog.html delete mode 100644 doc-tool/resources/_layouts/doc.html create mode 100644 doc-tool/resources/_layouts/sidebar.html create mode 100644 docs/docs/usage/dottydoc.md (limited to 'project') diff --git a/doc-tool/resources/_layouts/api-page.html b/doc-tool/resources/_layouts/api-page.html index 0e39f9d91..f45a8bab4 100644 --- a/doc-tool/resources/_layouts/api-page.html +++ b/doc-tool/resources/_layouts/api-page.html @@ -1,5 +1,5 @@ --- -layout: doc +layout: sidebar extraCSS: - css/api-page.css --- diff --git a/doc-tool/resources/_layouts/blog-page.html b/doc-tool/resources/_layouts/blog-page.html new file mode 100644 index 000000000..b99a16b9c --- /dev/null +++ b/doc-tool/resources/_layouts/blog-page.html @@ -0,0 +1,28 @@ +--- +layout: sidebar +--- + +
    +

    + {{ page.date | date: '%B %d, %Y' }} +

    +

    {{ page.title }}

    + {% if page.subTitle %} +

    {{ page.subTitle }}

    + {% endif %} +
    + +
    + {{ content }} +
    + +{% if page.author %} +
    + {% if page.authorImg %} + + {% endif %} + + {% if page.authorImg == null %}- {% endif %}{{ page.author }} + +
    +{% endif %} diff --git a/doc-tool/resources/_layouts/blog.html b/doc-tool/resources/_layouts/blog.html deleted file mode 100644 index d7a08414a..000000000 --- a/doc-tool/resources/_layouts/blog.html +++ /dev/null @@ -1,28 +0,0 @@ ---- -layout: doc ---- - -
    -

    - {{ page.date | date: '%B %d, %Y' }} -

    -

    {{ page.title }}

    - {% if page.subTitle %} -

    {{ page.subTitle }}

    - {% endif %} -
    - -
    - {{ content }} -
    - -{% if page.author %} -
    - {% if page.authorImg %} - - {% endif %} - - {% if page.authorImg == null %}- {% endif %}{{ page.author }} - -
    -{% endif %} diff --git a/doc-tool/resources/_layouts/doc-page.html b/doc-tool/resources/_layouts/doc-page.html index 876e90c95..14220aef7 100644 --- a/doc-tool/resources/_layouts/doc-page.html +++ b/doc-tool/resources/_layouts/doc-page.html @@ -1,5 +1,5 @@ --- -layout: doc +layout: sidebar ---

    {{ page.title }}

    diff --git a/doc-tool/resources/_layouts/doc.html b/doc-tool/resources/_layouts/doc.html deleted file mode 100644 index b3947c884..000000000 --- a/doc-tool/resources/_layouts/doc.html +++ /dev/null @@ -1,49 +0,0 @@ ---- -layout: main ---- - -
    -
    - {% include "toc" %} -
      - {% if docs.size > 0 %} -
    • - API -
    • - {% endif %} - {% for pkg in docs %} -
    • - {{ pkg.name }} -
    • - {% for member in pkg.children %} - {% if member.kind == "object" and member.hasCompanion %} - {% elsif member.kind != "package" %} -
    • -
      - {% if member.hasCompanion %} - O - {% endif %} - {{ member.kind | first | capitalize }} -
      - {{ member.name }} -
    • - {% endif %} - {% endfor %} - {% endfor %} -
    -
    -
    - - {{ content }} -
    -
    - - - diff --git a/doc-tool/resources/_layouts/sidebar.html b/doc-tool/resources/_layouts/sidebar.html new file mode 100644 index 000000000..b3947c884 --- /dev/null +++ b/doc-tool/resources/_layouts/sidebar.html @@ -0,0 +1,49 @@ +--- +layout: main +--- + +
    +
    + {% include "toc" %} +
      + {% if docs.size > 0 %} +
    • + API +
    • + {% endif %} + {% for pkg in docs %} +
    • + {{ pkg.name }} +
    • + {% for member in pkg.children %} + {% if member.kind == "object" and member.hasCompanion %} + {% elsif member.kind != "package" %} +
    • +
      + {% if member.hasCompanion %} + O + {% endif %} + {{ member.kind | first | capitalize }} +
      + {{ member.name }} +
    • + {% endif %} + {% endfor %} + {% endfor %} +
    +
    +
    + + {{ content }} +
    +
    + + + diff --git a/doc-tool/resources/css/dottydoc.css b/doc-tool/resources/css/dottydoc.css index aa197de07..54f74b66f 100644 --- a/doc-tool/resources/css/dottydoc.css +++ b/doc-tool/resources/css/dottydoc.css @@ -26,6 +26,55 @@ div.index-wrapper { overflow-x: hidden; } +div#doc-page-container > h1 { + border-bottom: 1px solid #eee; + padding-bottom: 0.3em; +} + +div#doc-page-container > h1 { + margin: 3rem 0 0.5rem 0; +} + +div#doc-page-container > h3 { + font-size: 1.5rem; +} + +div#doc-page-container > h4 { + font-size: 1.25rem; +} + +div#doc-page-container > h5 { + font-size: 1rem; +} + +div#doc-page-container > h1 > a, +div#doc-page-container > h2 > a, +div#doc-page-container > h3 > a, +div#doc-page-container > h4 > a, +div#doc-page-container > h5 > a, +div#doc-page-container > h6 > a { + text-decoration: none; + color: #373a3c; +} + +div#doc-page-container > h1 > a:hover, +div#doc-page-container > h2 > a:hover, +div#doc-page-container > h3 > a:hover, +div#doc-page-container > h4 > a:hover, +div#doc-page-container > h5 > a:hover, +div#doc-page-container > h6 > a:hover { + text-decoration: underline; +} + +div#doc-page-container > h1 > a:focus, +div#doc-page-container > h2 > a:focus, +div#doc-page-container > h3 > a:focus, +div#doc-page-container > h4 > a:focus, +div#doc-page-container > h5 > a:focus, +div#doc-page-container > h6 > a:focus { + outline: none; +} + div#content-body { border-left: 1px solid #e0e0e0; box-shadow: -3px 0px 5px -2px rgba(0,0,0,0.14); @@ -232,7 +281,7 @@ div#doc-page-container { } div#doc-page-container > p + h1 { - margin-bottom: 40px; + margin-bottom: 20px; } div#post-footer > img#author-image { diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/BlogPost.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/BlogPost.scala index 4683ed5f9..f68157e40 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/BlogPost.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/BlogPost.scala @@ -9,17 +9,22 @@ import dotc.config.Printers.dottydoc import MapOperations._ +/** + * A `BlogPost` represents the parsed posts from `./blog/_posts/` + * each post must be named according to the format + * `YYYY-MM-DD-title.{md,html}` + */ class BlogPost( val title: String, val url: String, val date: String, val content: String, firstParagraph: String, - val excerptSep: Option[String], + val excerpt_separator: Option[String], val categories: JList[String] ) { import scala.collection.JavaConverters._ - lazy val excerpt: String = excerptSep match { + lazy val excerpt: String = excerpt_separator match { case Some(str) => content.split(str).head case _ => firstParagraph } @@ -29,7 +34,7 @@ class BlogPost( "date" -> date, "url" -> url, "excerpt" -> excerpt, - "excerpt_separator" -> excerptSep.getOrElse(""), + "excerpt_separator" -> excerpt_separator.getOrElse(""), "content" -> content, "categories" -> categories ).asJava diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala index ace52725d..895668df2 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala @@ -17,6 +17,7 @@ import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension import com.vladsch.flexmark.ext.emoji.EmojiExtension import com.vladsch.flexmark.ext.autolink.AutolinkExtension +import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension import com.vladsch.flexmark.ext.front.matter.YamlFrontMatterExtension import com.vladsch.flexmark.util.options.{ DataHolder, MutableDataSet } @@ -292,10 +293,10 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma val defaultLayouts: Map[String, String] = Map( "main" -> "/_layouts/main.html", - "doc" -> "/_layouts/doc.html", + "sidebar" -> "/_layouts/sidebar.html", "doc-page" -> "/_layouts/doc-page.html", "api-page" -> "/_layouts/api-page.html", - "blog" -> "/_layouts/blog.html", + "blog-page" -> "/_layouts/blog-page.html", "index" -> "/_layouts/index.html" ).mapValues(getResource) @@ -362,6 +363,7 @@ object Site { TablesExtension.create(), TaskListExtension.create(), AutolinkExtension.create(), + AnchorLinkExtension.create(), EmojiExtension.create(), YamlFrontMatterExtension.create(), StrikethroughExtension.create() diff --git a/doc-tool/test/dotty/tools/dottydoc/staticsite/SiteTests.scala b/doc-tool/test/dotty/tools/dottydoc/staticsite/SiteTests.scala index bb24eb9fb..ba431a5c9 100644 --- a/doc-tool/test/dotty/tools/dottydoc/staticsite/SiteTests.scala +++ b/doc-tool/test/dotty/tools/dottydoc/staticsite/SiteTests.scala @@ -19,7 +19,7 @@ class SiteTests extends DottyDocTest { assert(site.root.exists && site.root.isDirectory, s"'${site.root.getName}' is not a directory") - val expectedLayouts = Set("main", "index", "blog", "doc", "doc-page", "api-page") + val expectedLayouts = Set("main", "index", "sidebar", "blog-page", "doc-page", "api-page") assert(site.layouts.keys == expectedLayouts, s"Incorrect layouts in: ${site.layouts.keys}, expected: $expectedLayouts") } diff --git a/docs/blog/index.html b/docs/blog/index.html index b821a25cc..b4725def7 100644 --- a/docs/blog/index.html +++ b/docs/blog/index.html @@ -1,5 +1,5 @@ --- -layout: blog +layout: blog-page title: "Blog" --- diff --git a/docs/docs/usage/dottydoc.md b/docs/docs/usage/dottydoc.md new file mode 100644 index 000000000..bbfae7081 --- /dev/null +++ b/docs/docs/usage/dottydoc.md @@ -0,0 +1,260 @@ +--- +layout: doc-page +title: Dottydoc +--- + +Dottydoc is a tool to generate a combined documentation and API reference for +your project. + +In previous versions of the Scaladoc tool, there is a big divide between what +is documentation and what is API reference. Dottydoc allows referencing, citing +and rendering parts of your API in your documentation, thus allowing the two to +blend naturally. + +To do this, Dottydoc is very similar to what [Jekyll](http://jekyllrb.com/) +provides in form of static site generation. As you probably guessed, this +whole site was created using Dottydoc. + +Creating a site is just as simple as in Jekyll. The site root contains the +layout of the site and all files placed here will be either considered static, +or processed for template expansion. + +The files that are considered for template expansion must end in `*.{html,md}` +and will from here on be referred to as "template files" or "templates". + +A simple "hello world" site could look something like this: + +``` +├── docs +│ └── getting-started.md +└── index.html +``` + +This will give you a site with the following endpoints: + +``` +_site/index.html +_site/docs/getting-started.html +``` + +Just as with Jekyll, the site is rendered in a `_site` directory. + +Using existing Templates and Layouts +==================================== +Dottydoc uses the [Liquid](https://shopify.github.io/liquid/) templating engine +and provides a number of custom filters and tags specific to Scala +documentation. + +In Dottydoc, all templates can contain YAML front-matter. The front-matter +is parsed and put into the `page` variable available in templates via Liquid. + +To perform template expansion, Dottydoc looks at `layout` in the front-matter. +Here's a simple example of the templating system in action, `index.html`: + +```html +--- +layout: main +--- + +

    Hello world!

    +``` + +With a simple main template like this: + +{% raw %} +```html + + + Hello, world! + + + {{ content }} + + +``` + +Would result in `{{ content }}` being replaced by `

    Hello world!

    ` from +the `index.html` file. +{% endraw %} + +Layouts must be placed in a `_layouts` directory in the site root: + +``` +├── _layouts +│ └── main.html +├── docs +│ └── getting-started.md +└── index.html +``` + +It is also possible to use one of the [default layouts](#default-layouts) that ship with Dottydoc. + +Blog +==== +Dottydoc also allows for a simple blogging platform in the same vein as Jekyll. +Blog posts are placed within the `./blog/_posts` directory and have to be on +the form `year-month-day-title.{md,html}`. + +An example of this would be: + +``` +├── blog +│ └── _posts +│ └── 2016-12-05-implicit-function-types.md +└── index.html +``` + +To be rendered as templates, each blog post should have front-matter and a +`layout` declaration. + +The posts are also available in the variable `site.posts` throughout the site. +The fields of these objects are the same as in +[BlogPost](dotty.tools.dottydoc.staticsite.BlogPost). + +Includes +======== +In Liquid, there is a concept of include tags, these are used in templates to +include other de facto templates: + +```html +
    + {% raw %}{% include "sidebar.html" %}{% endraw %} +
    +``` + +You can leave out the file extension if your include ends in `.html`. + +Includes need to be kept in `_includes` in the site root. Dottydoc provides a +couple of [default includes](#default-includes), but the user-specified +includes may override these. + +An example structure with an include file "sidebar.html": + +``` +├── _includes +│ └── sidebar.html +├── blog +│ ├── _posts +│ │ └── 2016-12-05-implicit-function-types.md +│ └── index.md +└── index.html +``` + +Sidebar +======= +Dottydoc gives you the ability to create your own custom table of contents, +this can either be achieved by overriding the `toc.html` include - or by +providing a `sidebar.yml` file in the site root: + +```yaml +sidebar: + - title: Blog + url: blog/index.html + - title: Docs + url: docs/index.html + - title: Usage + subsection: + - title: Dottydoc + url: docs/usage/dottydoc.html + - title: sbt-projects + url: docs/usage/sbt-projects.html +``` + +The `sidebar` key is mandatory, as well as `title` for each element. The +default table of contents allows you to have subsections - albeit the current +depth limit is 2 - we'd love to see this change, contributions welcome! + +The items which have the `subsection` key, may not have a `url` key in the +current scheme. A site root example with this could be: + +``` +├── blog +│ └── _posts +│ └── 2016-12-05-implicit-function-types.md +├── index.html +└── sidebar.yml +``` + +Dottydoc Specific Tags and Behavior +==================================== +Linking to API +-------------- +If you for instance, want to link to `scala.collection.immutable.Seq` in a +markdown file, you can simply use the canonical path in your url: + +```markdown +[Seq](scala.collection.immutable.Seq) +``` + +Linking to members is done in the same fashion: + +```markdown +[Seq](scala.collection.immutable.Seq.isEmpty) +``` + +Dottydoc denotes objects by ending their names in "$". To select `Object.range` +you'd therefore write: + +```markdown +[Object.range](scala.collection.immutable.List$.range) +``` + +Rendering Docstrings +-------------------- +Sometimes you end up duplicating the docstring text in your documentation, +therefore Dottydoc makes it easy to render this inline: + +```html +{% raw %}{% docstring "scala.collection.immutable.Seq" %}{% endraw %} +``` + +Other extensions +---------------- +We would love to have your feedback on what you think would be good in order to +render the documentation you want! Perhaps you'd like to render method +definitions or members? Let us know by filing +[issues](https://github.com/lampepfl/dotty/issues/new)! + +Default Layouts +=============== +main.html +--------- +A wrapper for all other layouts, includes a default `` with included +JavaScripts and CSS style-sheets. + +### Variables ### +* `content`: placed in `` tag +* `extraCSS`: a list of relative paths to extra CSS style-sheets for the site +* `extraJS`: a list of relative paths to extra JavaScripts for the site +* `title`: the `` of the page + +sidebar.html +------------ +Sidebar uses `main.html` as its parent layout. It adds a sidebar generated from +a YAML file (if exists), as well as the index for the project API. + +### Variables ### +* `content`: placed in a `<div>` with class `content-body` +* `docs`: the API docs generated from supplied source files, this is included by + default and does not need to be specified. + +doc-page.html +------------- +Doc page is used for pages that need a sidebar and provides a small wrapper for +the included {% raw %}`{{ content}}`{% endraw %}. + +api-page.html +------------- +The last two layouts are special, in that they are treated specially by +Dottydoc. The input to the API page is a documented +[Entity](dotty.tools.dottydoc.model.Entity). As such, this page can be changed +to alter the way Dottydoc renders API documentation. + +blog-page.html +-------------- +A blog page uses files placed in `./blog/_posts/` as input to render a blog. + +Default Includes +================ +* `scala-logo.svg`: the scala in dotty version as svg +* `toc.html`: the default table of contents template diff --git a/docs/sidebar.yml b/docs/sidebar.yml index 6353b3c90..7ffa1f5b7 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -9,6 +9,8 @@ sidebar: url: docs/usage/cbt-projects.html - title: sbt-projects url: docs/usage/sbt-projects.html + - title: Dottydoc + url: docs/usage/dottydoc.html - title: Migrating url: docs/usage/migrating.html - title: Contributing diff --git a/project/Build.scala b/project/Build.scala index 0abdc99be..d104544c5 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -192,6 +192,7 @@ object DottyBuild extends Build { "com.vladsch.flexmark" % "flexmark-ext-gfm-tasklist" % "0.11.1", "com.vladsch.flexmark" % "flexmark-ext-gfm-tables" % "0.11.1", "com.vladsch.flexmark" % "flexmark-ext-autolink" % "0.11.1", + "com.vladsch.flexmark" % "flexmark-ext-anchorlink" % "0.11.1", "com.vladsch.flexmark" % "flexmark-ext-emoji" % "0.11.1", "com.vladsch.flexmark" % "flexmark-ext-gfm-strikethrough" % "0.11.1", "com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % "0.11.1", -- cgit v1.2.3 From 483ac5340db262adb5efcf747a97dc9f25bc0208 Mon Sep 17 00:00:00 2001 From: Felix Mulder <felix.mulder@gmail.com> Date: Tue, 24 Jan 2017 18:26:15 +0100 Subject: Fix javadoc indentation style parsing --- compiler/src/dotty/tools/dotc/core/Phases.scala | 12 ++-- .../dotc/transform/IsInstanceOfEvaluator.scala | 52 +++++++------- .../src/dotty/tools/dottydoc/DocCompiler.scala | 22 +++--- doc-tool/src/dotty/tools/dottydoc/DocDriver.scala | 4 +- .../src/dotty/tools/dottydoc/DocFrontEnd.scala | 10 +-- .../dotty/tools/dottydoc/api/scala/Dottydoc.scala | 42 +++++------ .../dottydoc/model/comment/CommentCleaner.scala | 2 +- .../dottydoc/model/comment/CommentRegex.scala | 2 +- doc-tool/test/CommentCleanerTest.scala | 83 ++++++++++++++++++++++ project/Build.scala | 32 +++++---- 10 files changed, 176 insertions(+), 85 deletions(-) create mode 100644 doc-tool/test/CommentCleanerTest.scala (limited to 'project') diff --git a/compiler/src/dotty/tools/dotc/core/Phases.scala b/compiler/src/dotty/tools/dotc/core/Phases.scala index b066943dd..7bba88542 100644 --- a/compiler/src/dotty/tools/dotc/core/Phases.scala +++ b/compiler/src/dotty/tools/dotc/core/Phases.scala @@ -267,12 +267,12 @@ object Phases { trait Phase extends DotClass { /** A name given to the `Phase` that can be used to debug the compiler. For - * instance, it is possible to print trees after a given phase using: - * - * ```bash - * $ ./bin/dotc -Xprint:<phaseNameHere> sourceFile.scala - * ``` - */ + * instance, it is possible to print trees after a given phase using: + * + * ```bash + * $ ./bin/dotc -Xprint:<phaseNameHere> sourceFile.scala + * ``` + */ def phaseName: String /** List of names of phases that should precede this phase */ diff --git a/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala b/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala index e6b1f5aac..0c6ee7a18 100644 --- a/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala +++ b/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala @@ -8,27 +8,27 @@ import Contexts.Context, Types._, Constants._, Decorators._, Symbols._ import TypeUtils._, TypeErasure._, Flags._ /** Implements partial evaluation of `sc.isInstanceOf[Sel]` according to: - * - * | Sel\sc | trait | class | final class | - * | ----------: | :------------------------: | :------------------------: | :--------------: | - * | trait | ? | ? | statically known | - * | class | ? | false if classes unrelated | statically known | - * | final class | false if classes unrelated | false if classes unrelated | statically known | - * - * This is a generalized solution to raising an error on unreachable match - * cases and warnings on other statically known results of `isInstanceOf`. - * - * Steps taken: - * - * 1. `evalTypeApply` will establish the matrix and choose the appropriate - * handling for the case: - * - Sel/sc is a value class or scrutinee is `Any` - * - `handleStaticallyKnown` - * - `falseIfUnrelated` with `scrutinee <:< selector` - * - `handleFalseUnrelated` - * - leave as is (`happens`) - * 2. Rewrite according to steps taken in 1 - */ + * + * | Sel\sc | trait | class | final class | + * | ----------: | :------------------------: | :------------------------: | :--------------: | + * | trait | ? | ? | statically known | + * | class | ? | false if classes unrelated | statically known | + * | final class | false if classes unrelated | false if classes unrelated | statically known | + * + * This is a generalized solution to raising an error on unreachable match + * cases and warnings on other statically known results of `isInstanceOf`. + * + * Steps taken: + * + * 1. `evalTypeApply` will establish the matrix and choose the appropriate + * handling for the case: + * - Sel/sc is a value class or scrutinee is `Any` + * - `handleStaticallyKnown` + * - `falseIfUnrelated` with `scrutinee <:< selector` + * - `handleFalseUnrelated` + * - leave as is (`happens`) + * 2. Rewrite according to steps taken in 1 + */ class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer => import dotty.tools.dotc.ast.tpd._ @@ -37,15 +37,15 @@ class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer => val phaseName = "isInstanceOfEvaluator" /** Transforms a [TypeApply](dotty.tools.dotc.ast.Trees.TypeApply) in order to - * evaluate an `isInstanceOf` check according to the rules defined above. - */ + * evaluate an `isInstanceOf` check according to the rules defined above. + */ override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree = { val defn = ctx.definitions /** Handles the four cases of statically known `isInstanceOf`s and gives - * the correct warnings, or an error if statically known to be false in - * match - */ + * the correct warnings, or an error if statically known to be false in + * match + */ def handleStaticallyKnown(select: Select, scrutinee: Type, selector: Type, inMatch: Boolean, pos: Position): Tree = { val scrutineeSubSelector = scrutinee <:< selector if (!scrutineeSubSelector && inMatch) { diff --git a/doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala b/doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala index 081883597..708c26cc0 100644 --- a/doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala +++ b/doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala @@ -7,17 +7,17 @@ import dotc.core.Phases.Phase import dotc.Compiler /** Custom Compiler with phases for the documentation tool - * - * The idea here is to structure `dottydoc` around the new infrastructure. As - * such, dottydoc will itself be a compiler. It will, however, produce a format - * that can be used by other tools or web-browsers. - * - * Example: - * 1. Use the existing FrontEnd to typecheck the code being fed to dottydoc, - * wihtout discarding AnyVal interfaces - * 2. Create an AST that is serializable - * 3. Serialize to JS object - */ + * + * The idea here is to structure `dottydoc` around the new infrastructure. As + * such, dottydoc will itself be a compiler. It will, however, produce a format + * that can be used by other tools or web-browsers. + * + * Example: + * 1. Use the existing FrontEnd to typecheck the code being fed to dottydoc, + * wihtout discarding AnyVal interfaces + * 2. Create an AST that is serializable + * 3. Serialize to JS object + */ class DocCompiler extends Compiler { override def phases: List[List[Phase]] = List( List(new DocFrontEnd), diff --git a/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala b/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala index e5a2cc266..ba7edb4b6 100644 --- a/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala +++ b/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala @@ -12,8 +12,8 @@ import dotc.core.Comments.ContextDoc import staticsite.Site /** `DocDriver` implements the main entry point to the Dotty documentation - * tool. It's methods are used by the external scala and java APIs. - */ + * tool. It's methods are used by the external scala and java APIs. + */ class DocDriver extends Driver { import _root_.java.util.{ Map => JMap } import model.java._ diff --git a/doc-tool/src/dotty/tools/dottydoc/DocFrontEnd.scala b/doc-tool/src/dotty/tools/dottydoc/DocFrontEnd.scala index 30c5e3e87..606fd0fc6 100644 --- a/doc-tool/src/dotty/tools/dottydoc/DocFrontEnd.scala +++ b/doc-tool/src/dotty/tools/dottydoc/DocFrontEnd.scala @@ -6,11 +6,11 @@ import dotc.core.Contexts.Context import dotc.CompilationUnit /** `DocFrontEnd` uses the Dotty `FrontEnd` without discarding the AnyVal - * interfaces for Boolean, Int, Char, Long, Byte etc. - * - * It currently still throws away Java sources by overriding - * `discardAfterTyper`. - */ + * interfaces for Boolean, Int, Char, Long, Byte etc. + * + * It currently still throws away Java sources by overriding + * `discardAfterTyper`. + */ class DocFrontEnd extends FrontEnd { override protected def discardAfterTyper(unit: CompilationUnit)(implicit ctx: Context) = unit.isJava diff --git a/doc-tool/src/dotty/tools/dottydoc/api/scala/Dottydoc.scala b/doc-tool/src/dotty/tools/dottydoc/api/scala/Dottydoc.scala index 1d0891bc2..9d00b08a3 100644 --- a/doc-tool/src/dotty/tools/dottydoc/api/scala/Dottydoc.scala +++ b/doc-tool/src/dotty/tools/dottydoc/api/scala/Dottydoc.scala @@ -7,27 +7,27 @@ import scala.collection.Map import java.net.URL /** The Dottydoc API is fairly simple. The tool creates an index by calling: - * `createIndex` with the same argument list as you would the compiler - e.g: - * - * ```scala - * val array: Array[String] = Array( - * "-language:Scala2" - * ) - * - * val index: Map[String, Package] = createIndex(array) - * ``` - * - * Once the index has been generated, the tool can also build a documentation - * API given a Mustache template and a flat resources structure (i.e. absolute - * paths to each resource, which will be put in the same directory). - * - * ```scala - * buildDocs("path/to/output/dir", templateURL, resources, index) - * ``` - * - * The tool can also generate JSON from the created index using `indexToJson` - * or directly using `createJsonIndex` - */ + * `createIndex` with the same argument list as you would the compiler - e.g: + * + * ```scala + * val array: Array[String] = Array( + * "-language:Scala2" + * ) + * + * val index: Map[String, Package] = createIndex(array) + * ``` + * + * Once the index has been generated, the tool can also build a documentation + * API given a Mustache template and a flat resources structure (i.e. absolute + * paths to each resource, which will be put in the same directory). + * + * ```scala + * buildDocs("path/to/output/dir", templateURL, resources, index) + * ``` + * + * The tool can also generate JSON from the created index using `indexToJson` + * or directly using `createJsonIndex` + */ trait Dottydoc extends DocDriver { /** Creates index from compiler arguments */ def createIndex(args: Array[String]): Map[String, Package] = diff --git a/doc-tool/src/dotty/tools/dottydoc/model/comment/CommentCleaner.scala b/doc-tool/src/dotty/tools/dottydoc/model/comment/CommentCleaner.scala index 27b0ff977..30b3b0de0 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/comment/CommentCleaner.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/comment/CommentCleaner.scala @@ -20,6 +20,6 @@ trait CommentCleaner { SafeTags.replaceAllIn(javadoclessComment, { mtch => _root_.java.util.regex.Matcher.quoteReplacement(safeTagMarker + mtch.matched + safeTagMarker) }) - markedTagComment.lines.toList map (cleanLine(_)) + markedTagComment.lines.toList map (cleanLine) } } diff --git a/doc-tool/src/dotty/tools/dottydoc/model/comment/CommentRegex.scala b/doc-tool/src/dotty/tools/dottydoc/model/comment/CommentRegex.scala index 2d75b0c66..faefd19a7 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/comment/CommentRegex.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/comment/CommentRegex.scala @@ -11,7 +11,7 @@ object Regexes { * one leading whitespace and all trailing whitespace */ val CleanCommentLine = - new Regex("""(?:\s*\*\s?)?(.*)""") + new Regex("""(?:\s*\*\s?\s?)?(.*)""") /** Dangerous HTML tags that should be replaced by something safer, * such as wiki syntax, or that should be dropped diff --git a/doc-tool/test/CommentCleanerTest.scala b/doc-tool/test/CommentCleanerTest.scala new file mode 100644 index 000000000..5cf5614c4 --- /dev/null +++ b/doc-tool/test/CommentCleanerTest.scala @@ -0,0 +1,83 @@ +package dotty.tools +package dottydoc + +import org.junit.Test +import org.junit.Assert._ + +import model.comment.CommentCleaner + +class CommentCleanerTest extends CommentCleaner { + @Test def simpleOneliner = { + assertEquals(List("lol"), clean("/** lol */")) + } + + @Test def multiline = { + val docstring = clean { + """|/** First + | * Second + | */ + |""".stripMargin + } + + assertEquals(List("First", "Second", ""), docstring) + } + + @Test def multilineBad = { + val docstring = clean { + """|/** First + | * Second + | */ + |""".stripMargin + } + + assertEquals(List("First", " Second", ""), docstring) + } + + @Test def multilineWorse = { + val docstring = clean { + """|/** First + | * Second + | * Third + | */ + |""".stripMargin + } + + assertEquals(List("First", " Second", "Third", ""), docstring) + } + + @Test def multilineFirstNoSpace = { + val docstring = clean { + """|/**First + | * Second + | * Third + | */ + |""".stripMargin + } + + assertEquals(List("First", " Second", "Third", ""), docstring) + } + + @Test def multilineFirstTwoSpaces = { + val docstring = clean { + """|/** First + | * Second + | * Third + | */ + |""".stripMargin + } + + assertEquals(List("First", " Second", "Third", ""), docstring) + } + + @Test def multilineFirstThreeSpaces = { + val docstring = clean { + """|/** First + | * Second + | * Third + | */ + |""".stripMargin + } + + assertEquals(List(" First", " Second", "Third", ""), docstring) + } +} diff --git a/project/Build.scala b/project/Build.scala index d104544c5..a6505a12c 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -55,6 +55,12 @@ object DottyBuild extends Build { // Compiles the documentation and static site lazy val genDocs = inputKey[Unit]("run dottydoc to generate static documentation site") + /** Dottydoc deps */ + lazy val dottydocDeps = SettingKey[Seq[ModuleID]]( + "dottydocDeps", + "dottydoc dependencies, should be moved to a dottydoc sbt subproject eventually" + ) + override def settings: Seq[Setting[_]] = { super.settings ++ Seq( scalaVersion in Global := scalacVersion, @@ -180,26 +186,28 @@ object DottyBuild extends Build { //http://stackoverflow.com/questions/10472840/how-to-attach-sources-to-sbt-managed-dependencies-in-scala-ide#answer-11683728 com.typesafe.sbteclipse.plugin.EclipsePlugin.EclipseKeys.withSource := true, + dottydocDeps := Seq( + "com.vladsch.flexmark" % "flexmark" % "0.11.1", + "com.vladsch.flexmark" % "flexmark-ext-gfm-tasklist" % "0.11.1", + "com.vladsch.flexmark" % "flexmark-ext-gfm-tables" % "0.11.1", + "com.vladsch.flexmark" % "flexmark-ext-autolink" % "0.11.1", + "com.vladsch.flexmark" % "flexmark-ext-anchorlink" % "0.11.1", + "com.vladsch.flexmark" % "flexmark-ext-emoji" % "0.11.1", + "com.vladsch.flexmark" % "flexmark-ext-gfm-strikethrough" % "0.11.1", + "com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % "0.11.1", + "com.fasterxml.jackson.dataformat" % "jackson-dataformat-yaml" % "2.8.6", + "nl.big-o" % "liqp" % "0.6.7" + ), + // get libraries onboard partestDeps := Seq(scalaCompiler, "org.scala-lang" % "scala-reflect" % scalacVersion, "org.scala-lang" % "scala-library" % scalacVersion % "test"), libraryDependencies ++= partestDeps.value, + libraryDependencies ++= dottydocDeps.value, libraryDependencies ++= Seq("org.scala-lang.modules" %% "scala-xml" % "1.0.1", "org.scala-lang.modules" %% "scala-partest" % "1.0.11" % "test", - dottyOrganization % "dottydoc-client" % "0.1.0", - "com.vladsch.flexmark" % "flexmark" % "0.11.1", - "com.vladsch.flexmark" % "flexmark-ext-gfm-tasklist" % "0.11.1", - "com.vladsch.flexmark" % "flexmark-ext-gfm-tables" % "0.11.1", - "com.vladsch.flexmark" % "flexmark-ext-autolink" % "0.11.1", - "com.vladsch.flexmark" % "flexmark-ext-anchorlink" % "0.11.1", - "com.vladsch.flexmark" % "flexmark-ext-emoji" % "0.11.1", - "com.vladsch.flexmark" % "flexmark-ext-gfm-strikethrough" % "0.11.1", - "com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % "0.11.1", - "com.fasterxml.jackson.dataformat" % "jackson-dataformat-yaml" % "2.8.6", - "nl.big-o" % "liqp" % "0.6.7", "com.novocode" % "junit-interface" % "0.11" % "test", - "com.github.spullara.mustache.java" % "compiler" % "0.9.3", "com.typesafe.sbt" % "sbt-interface" % sbtVersion.value), // enable improved incremental compilation algorithm incOptions := incOptions.value.withNameHashing(true), -- cgit v1.2.3 From 6a2d1e0eb1005aa2e3567f256c6e259ede2f6ea7 Mon Sep 17 00:00:00 2001 From: Felix Mulder <felix.mulder@gmail.com> Date: Thu, 2 Feb 2017 11:56:25 +0100 Subject: Add script to update orphan gh-pages branch --- .drone.yml | 17 +++++++++++++ .drone.yml.sig | 1 + project/scripts/genDocs | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 .drone.yml.sig create mode 100755 project/scripts/genDocs (limited to 'project') diff --git a/.drone.yml b/.drone.yml index 16a5aff49..512f5a39e 100644 --- a/.drone.yml +++ b/.drone.yml @@ -6,6 +6,23 @@ pipeline: - ln -s /var/cache/drone/scala-scala scala-scala - ./scripts/update-scala-library - sbt -J-Xmx4096m -J-XX:ReservedCodeCacheSize=512m -J-XX:MaxMetaspaceSize=1024m -Ddotty.drone.mem=4096m -ivy /var/cache/drone/ivy2 "${TEST}" + when: + branch: + exclude: gh-pages + + documentation: + image: lampepfl/dotty:latest + pull: true + commands: + - ./project/scripts/genDocs "${TEST}" $BOT_PASS + when: + branch: master + + slack: + image: plugins/slack + channel: dotty + when: + branch: master matrix: TEST: diff --git a/.drone.yml.sig b/.drone.yml.sig new file mode 100644 index 000000000..23edbaae9 --- /dev/null +++ b/.drone.yml.sig @@ -0,0 +1 @@ +eyJhbGciOiJIUzI1NiJ9.cGlwZWxpbmU6CiAgdGVzdDoKICAgIGltYWdlOiBsYW1wZXBmbC9kb3R0eTpsYXRlc3QKICAgIHB1bGw6IHRydWUKICAgIGNvbW1hbmRzOgogICAgICAtIGxuIC1zIC92YXIvY2FjaGUvZHJvbmUvc2NhbGEtc2NhbGEgc2NhbGEtc2NhbGEKICAgICAgLSAuL3NjcmlwdHMvdXBkYXRlLXNjYWxhLWxpYnJhcnkKICAgICAgLSBzYnQgLUotWG14NDA5Nm0gLUotWFg6UmVzZXJ2ZWRDb2RlQ2FjaGVTaXplPTUxMm0gLUotWFg6TWF4TWV0YXNwYWNlU2l6ZT0xMDI0bSAtRGRvdHR5LmRyb25lLm1lbT00MDk2bSAtaXZ5IC92YXIvY2FjaGUvZHJvbmUvaXZ5MiAiJHtURVNUfSIKICAgIHdoZW46CiAgICAgIGJyYW5jaDoKICAgICAgICBleGNsdWRlOiBnaC1wYWdlcwoKICBkb2N1bWVudGF0aW9uOgogICAgaW1hZ2U6IGxhbXBlcGZsL2RvdHR5OmxhdGVzdAogICAgcHVsbDogdHJ1ZQogICAgY29tbWFuZHM6CiAgICAgIC0gLi9wcm9qZWN0L3NjcmlwdHMvZ2VuRG9jcyAiJHtURVNUfSIgJEJPVF9QQVNTCiAgICB3aGVuOgogICAgICBicmFuY2g6IG1hc3RlcgoKICBzbGFjazoKICAgIGltYWdlOiBwbHVnaW5zL3NsYWNrCiAgICBjaGFubmVsOiBkb3R0eQogICAgd2hlbjoKICAgICAgYnJhbmNoOiBtYXN0ZXIKCm1hdHJpeDoKICBURVNUOgogICAgLSB0ZXN0CiAgICAtIDtwdWJsaXNoTG9jYWw7ZG90dHktYm9vdHN0cmFwcGVkL3Rlc3QKICAgIC0gcGFydGVzdC1vbmx5LW5vLWJvb3RzdHJhcCAtLXNob3ctZGlmZiAtLXZlcmJvc2UKICAgIC0gcGFydGVzdC1vbmx5IC0tc2hvdy1kaWZmIC0tdmVyYm9zZQo.l7I2yJ5gewe0ObfP09MyJ9iGlXaPffen5Sh3HjS2oKs \ No newline at end of file diff --git a/project/scripts/genDocs b/project/scripts/genDocs new file mode 100755 index 000000000..b8d0ba254 --- /dev/null +++ b/project/scripts/genDocs @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +# Usage: ./genDocs <test variable> <dotty-bot password> + +set -e +# set extended glob, needed for rm everything but x +shopt -s extglob + +if [ "$1" = "test" ]; then + + # make sure that BOT_PASS is set + if [ -z ${2+x} ]; then + echo "BOT_PASS unset, unable to push without password" 1>&2 + exit 1 + else + BOT_PASS=$2 + fi + + echo "Working directory: $PWD" + + # this command will generate docs in $PWD/docs/_site + sbt -J-Xmx4096m \ + -J-XX:ReservedCodeCacheSize=512m \ + -J-XX:MaxMetaspaceSize=1024m \ + -Ddotty.drone.mem=4096m \ + -ivy /var/cache/drone/ivy2 \ + "genDocs" + + # make sure that the previous command actually succeeded + if [ ! -d "$PWD/docs/_site" ]; then + echo "Output directory did not exist: $PWD/docs/_site" 1>&2 + exit 1 + fi + + # save current head for commit message in gh-pages + GIT_HEAD=$(git rev-parse HEAD) + + # check out correct branch + git fetch origin gh-pages:gh-pages + git checkout gh-pages + + # move newly generated _site dir to $PWD + mv $PWD/docs/_site . + + # remove everything BUT _site dir + rm -rf !(_site) + + # copy new contents to $PWD + mv _site/* . + + # remove now empty _site dir + rm -rf _site + + # set github credentials + git config user.name "dotty-bot" + git config user.email "felix.mulder@epfl.ch" + + # add all contents of $PWD to commit + git add -A + git commit -m "Update gh-pages site for $GIT_HEAD" + + # push using dotty-bot to origin + git push https://dotty-bot:$BOT_PASS@github.com/lampepfl/dotty.git +else + # wrong parameter passed, should only generate docs if argument is "test" + # to avoid multiple site gens + echo "Not generating docs for $1" +fi -- cgit v1.2.3