From 659f18608b6fe3725c1247f73b1ad9d405679f6a Mon Sep 17 00:00:00 2001 From: Krzysztof Romanowski Date: Thu, 19 Nov 2020 19:35:36 +0100 Subject: [PATCH 01/11] Do not fail when rendering briefs In case of no paragraph or exception use '...' --- scala3doc/src/dotty/dokka/site/LoadedTemplate.scala | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scala3doc/src/dotty/dokka/site/LoadedTemplate.scala b/scala3doc/src/dotty/dokka/site/LoadedTemplate.scala index dad0136b375d..bd5fa05ac43c 100644 --- a/scala3doc/src/dotty/dokka/site/LoadedTemplate.scala +++ b/scala3doc/src/dotty/dokka/site/LoadedTemplate.scala @@ -20,8 +20,15 @@ case class LazyEntry(getKey: String, value: () => String) extends JMapEntry[Stri case class LoadedTemplate(templateFile: TemplateFile, children: List[LoadedTemplate], file: File): private def brief(ctx: StaticSiteContext): String = - val code = Jsoup.parse(resolveToHtml(ctx).code) - code.select("p").first().outerHtml() + try + val code = Jsoup.parse(resolveToHtml(ctx).code) + Option(code.select("p").first()).fold("...")(_.outerHtml()) + catch + case e: Throwable => + // TODO (https://github.com/lampepfl/scala3doc/issues/238): provide proper error handling + println(s"[ERROR] Unable to process brief for ${templateFile.file}") + e.printStackTrace() + "..." def lazyTemplateProperties(ctx: StaticSiteContext): JMap[String, Object] = new java.util.AbstractMap[String, Object](): def entrySet(): JSet[JMapEntry[String, Object]] = From cf5fcc22d5bcb55be35a98810d4c0a1a654db9ce Mon Sep 17 00:00:00 2001 From: Krzysztof Romanowski Date: Thu, 19 Nov 2020 19:37:03 +0100 Subject: [PATCH 02/11] Sidebar is able to accept directories --- .../dotty/dokka/site/StaticSiteContext.scala | 20 +++++++++++++------ .../src/dotty/dokka/site/processors.scala | 5 +++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/scala3doc/src/dotty/dokka/site/StaticSiteContext.scala b/scala3doc/src/dotty/dokka/site/StaticSiteContext.scala index d4acc738e197..74c43792f75f 100644 --- a/scala3doc/src/dotty/dokka/site/StaticSiteContext.scala +++ b/scala3doc/src/dotty/dokka/site/StaticSiteContext.scala @@ -44,19 +44,23 @@ class StaticSiteContext(val root: File, sourceSets: Set[SourceSetWrapper], args: lazy val mainPages: Seq[StaticPageNode] = templates.map(templateToPage) + val docsPath = root.toPath.resolve("docs") + lazy val allPages: Seq[StaticPageNode] = sideBarConfig.fold(mainPages){ sidebar => def flattenPages(p: StaticPageNode): Set[Path] = Set(p.template.file.toPath) ++ p.getChildren.asScala.collect { case p: StaticPageNode => flattenPages(p) }.flatten val mainFiles = mainPages.toSet.flatMap(flattenPages) - val docsPath = root.toPath.resolve("docs") + val allPaths = if !Files.exists(docsPath) then Nil else Files.walk(docsPath, FileVisitOption.FOLLOW_LINKS).iterator().asScala.toList val orphanedFiles = allPaths.filterNot(mainFiles.contains).filter { p => val name = p.getFileName.toString - name.endsWith(".md") || name.endsWith(".html") + def isSupported = name.endsWith(".md") || name.endsWith(".html") + def notIndex = name == "index.md" || name == "index.html" + isSupported && notIndex } val orphanedTemplates = orphanedFiles.flatMap(p => loadTemplate(p.toFile, isBlog = false)) @@ -114,10 +118,14 @@ class StaticSiteContext(val root: File, sourceSets: Set[SourceSetWrapper], args: private def loadSidebarContent(entry: Sidebar): LoadedTemplate = entry match case Sidebar.Page(title, url) => val isBlog = title == "Blog" - val path = if isBlog then "blog" else url.stripSuffix(".html") + ".md" - val file = root.toPath.resolve(path) // Add support for .html files! - val LoadedTemplate(template, children, tFile) = loadTemplate(file.toFile, isBlog).get // Add proper logging if file does not exisits - LoadedTemplate(template.copy(settings = template.settings + ("title" -> title)), children, tFile) + val path = if isBlog then "blog" else + if Files.exists(root.toPath.resolve(url)) then url + else url.stripSuffix(".html") + ".md" + + val file = root.toPath.resolve(path).toFile + val LoadedTemplate(template, children, _) = loadTemplate(file, isBlog).get // Add proper logging if file does not exisits + LoadedTemplate(template.copy(settings = template.settings + ("title" -> title), file = file), children, file) + case Sidebar.Category(title, nested) => // Add support for index.html/index.md files! val fakeFile = new File(root, title) diff --git a/scala3doc/src/dotty/dokka/site/processors.scala b/scala3doc/src/dotty/dokka/site/processors.scala index fcccd9f02f4f..75163f9f5cef 100644 --- a/scala3doc/src/dotty/dokka/site/processors.scala +++ b/scala3doc/src/dotty/dokka/site/processors.scala @@ -92,9 +92,10 @@ class SitePagesCreator(ctx: Option[StaticSiteContext]) extends BaseStaticSitePro override def transform(input: RootPageNode, ctx: StaticSiteContext): RootPageNode = val (contentPage, others) = input.getChildren.asScala.toList.partition { _.isInstanceOf[ContentPage] } val modifiedModuleRoot = processRootPage(input, contentPage) - val (indexes, children) = ctx.allPages.partition(_.template.isIndexPage()) + val (indexes, children) = ctx.allPages.partition(f => + f.template.isIndexPage() && f.template.file.toPath.getParent() == ctx.docsPath ) // TODO (https://github.com/lampepfl/scala3doc/issues/238): provide proper error handling - if (indexes.size > 1) println("ERROR: Multiple index pages found $indexes}") + if (indexes.size > 1) println(s"ERROR: Multiple index pages found ${indexes.map(_.template.file)}") val rootContent = indexes.headOption.fold(ctx.asContent(Text(), mkDRI(extra = "root_content")).get(0))(_.getContent) From 0fb402ac28dfc92484dc3b2a983d39d7589bd01c Mon Sep 17 00:00:00 2001 From: Krzysztof Romanowski Date: Thu, 19 Nov 2020 22:54:39 +0100 Subject: [PATCH 03/11] FIx breadcrumbs in static pages --- .../dokka/site/StaticSiteLocationProvider.scala | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scala3doc/src/dotty/dokka/site/StaticSiteLocationProvider.scala b/scala3doc/src/dotty/dokka/site/StaticSiteLocationProvider.scala index 3092446d6b5d..d66d58f2e936 100644 --- a/scala3doc/src/dotty/dokka/site/StaticSiteLocationProvider.scala +++ b/scala3doc/src/dotty/dokka/site/StaticSiteLocationProvider.scala @@ -24,9 +24,15 @@ class StaticSiteLocationProvider(ctx: DokkaContext, pageNode: RootPageNode) else { val path = jpath.asScala.toList val start = if (path.head == "--root--") List("docs") else path.take(1) - val pageName = page.template.file.getName - val dotIndex = pageName.lastIndexOf('.') - val newName = if (dotIndex < 0) pageName else pageName.substring(0, dotIndex) + // Dokka has a bug in location provider that does not properly handles relative paths for leaf nodes + // This forces us to not change default paths on non-leaf nodes + val newName = if page.getChildren.size() > 0 then path.last else + val pageName = page.template.file.getName + val dotIndex = pageName.lastIndexOf('.') + if (dotIndex < 0) pageName else pageName.substring(0, dotIndex) + + println(s"Using $newName for ${page.template.file} orignally: $path") + (start ++ path.drop(1).dropRight(1) ++ List(newName)).asJava } case page: ContentPage if page.getDri.contains(docsDRI) => From 1815dcfa2b304d619a0fb0fed5350415ce58d282 Mon Sep 17 00:00:00 2001 From: Krzysztof Romanowski Date: Thu, 19 Nov 2020 22:56:18 +0100 Subject: [PATCH 04/11] Add basic documentation --- docs/docs/usage/dottydoc.md | 2 +- docs/docs/usage/scala3doc/blog.md | 7 ++ docs/docs/usage/scala3doc/docComments.md | 7 ++ docs/docs/usage/scala3doc/index.md | 24 +++++ docs/docs/usage/scala3doc/specificTags.md | 29 +++++ docs/docs/usage/scala3doc/staticSite.md | 125 ++++++++++++++++++++++ docs/images/scala3doc-logo.png | Bin 0 -> 25641 bytes docs/sidebar.yml | 4 +- 8 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 docs/docs/usage/scala3doc/blog.md create mode 100644 docs/docs/usage/scala3doc/docComments.md create mode 100644 docs/docs/usage/scala3doc/index.md create mode 100644 docs/docs/usage/scala3doc/specificTags.md create mode 100644 docs/docs/usage/scala3doc/staticSite.md create mode 100644 docs/images/scala3doc-logo.png diff --git a/docs/docs/usage/dottydoc.md b/docs/docs/usage/dottydoc.md index dcf056a7d57b..f7e15b692d99 100644 --- a/docs/docs/usage/dottydoc.md +++ b/docs/docs/usage/dottydoc.md @@ -1,6 +1,6 @@ --- layout: doc-page -title: Dottydoc +title: Dottydoc [Legacy] --- Dottydoc is a tool to generate a combined documentation and API reference for diff --git a/docs/docs/usage/scala3doc/blog.md b/docs/docs/usage/scala3doc/blog.md new file mode 100644 index 000000000000..2d13ca155561 --- /dev/null +++ b/docs/docs/usage/scala3doc/blog.md @@ -0,0 +1,7 @@ +--- +title: Build-in blog +--- + +# {{page.title}} + +Scala3doc is capable to include blogposts. For now we support only simple blogposts but in future we plan to include more advanced features like tags. \ No newline at end of file diff --git a/docs/docs/usage/scala3doc/docComments.md b/docs/docs/usage/scala3doc/docComments.md new file mode 100644 index 000000000000..c6fd4c6aad4c --- /dev/null +++ b/docs/docs/usage/scala3doc/docComments.md @@ -0,0 +1,7 @@ +--- +title: API Documentation +--- + +# {{ page.title }} + +Scala3doc main feature is to create API documentation based on [doc comments](https://docs.scala-lang.org/style/scaladoc.html) known from scaladoc as well well as new syntax introduced in Scala 3. \ No newline at end of file diff --git a/docs/docs/usage/scala3doc/index.md b/docs/docs/usage/scala3doc/index.md new file mode 100644 index 000000000000..4af462a9c14d --- /dev/null +++ b/docs/docs/usage/scala3doc/index.md @@ -0,0 +1,24 @@ +--- +title: Scala3doc +--- + +![Scala3doc logo](/images/scala3doc-logo.png) + +Scala3doc is a doctool dedicated to work with Scala 3.0. Beside basic features similar to `javadoc` or `scaladoc`. As you probably guessed, this +whole site was created using scala3doc. + +{% for post in site.posts %} +## [{{ post.title }}](/{{ post.url }}) + +{{ post.excerpt }} + +[ (read more) ](/{{ post.url }}) + +{% endfor %} + +## 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 would like to render method +definitions or members? Let us know by filing +[issues](https://github.com/lampepfl/dotty/issues/new)! \ No newline at end of file diff --git a/docs/docs/usage/scala3doc/specificTags.md b/docs/docs/usage/scala3doc/specificTags.md new file mode 100644 index 000000000000..f684ff5da49c --- /dev/null +++ b/docs/docs/usage/scala3doc/specificTags.md @@ -0,0 +1,29 @@ +--- +title: Dottydoc Specific Tags and Behavior +--- + +# {{page.title}} + +Scala3doc extemds markdown with some unique behaviours such as linking to API. This can be used from within static documentation and blogpost to provide blend-in content. + +## 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) +``` + +Scala3doc denotes objects by ending their names in "$". To select `List.range` +you'd therefore write: + +```markdown +[List.range](scala.collection.immutable.List$.range) +``` \ No newline at end of file diff --git a/docs/docs/usage/scala3doc/staticSite.md b/docs/docs/usage/scala3doc/staticSite.md new file mode 100644 index 000000000000..29b04f167469 --- /dev/null +++ b/docs/docs/usage/scala3doc/staticSite.md @@ -0,0 +1,125 @@ +--- +title: Static docucmentation +--- + +# {{ page.title}} + +Scala3doc has similar functionalites to [Jekyll](http://jekyllrb.com/) to allow users to documentation in form of static sit alongside your APIs. Moreover having a combined tool allows provide reach interaction between those to such as linking thus allowing the two to +blend naturally. + +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 files in genrated documentation: + +``` +index.html +docs/getting-started.html +``` + +Scala3doc can transform both files and directories (to organize your documentation into tree-like structure). By default directories has title based on file name and has empty content. There is an option to include `index.html` or `index.md` (not both) to provide both content and properties like title (see [Properties](#properties)). + +## Properties + +Scala3doc uses the [Liquid](https://shopify.github.io/liquid/) templating engine +and provides a number of custom filters and tags specific to Scala +documentation. + +In Scala3doc, all templates can contain YAML front-matter. The front-matter +is parsed and put into the `page` variable available in templates via Liquid. + +Scala3doc uses some predefied properties to controls some aspect of page. + +Predefiend properties: + + - **title** provide page title that will be used in navigation and html metadata. + - **extraCss** additional `.css` files that will be included in this page. Paths should be relative to documentation root. **This setting is not exported to template engine** + - **extraJs** additional `.js` files that will be included in this page. Paths should be relative to documentation root. **This setting is not exported to template engine** + - **hasFrame** when set to `false` page will not include default layout (navigation, breadcrumbs etc.) but only token html wrapper to provide metadata and resources (js and css files) +- **layout** - predefined layout to use, see below + + +## Using existing Templates and Layouts + +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 +``` + +Sidebar +======= +Scala3doc by default use layout of files in `docs` directory to create table of content. There is also ability to override it 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 however it accepts both files and directories and latter can be used to provide deeper structures. + +The items which have the `subsection` does not accepts `url` section. + +``` +├── blog +│ └── _posts +│ └── 2016-12-05-implicit-function-types.md +├── index.html +└── sidebar.yml +``` diff --git a/docs/images/scala3doc-logo.png b/docs/images/scala3doc-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6958f32353448e5fb494e0dc16f2a0c2efe7ed12 GIT binary patch literal 25641 zcmeFX^9*q4lNd(;ts)GinO>@a0~7b+#QO$6f4@|R-kw&?gfflu!iE&;_^-J z`+c78AMw7M&-vkO&N(|fJ3DjDHTywJ;}t#*B@O@pz*l~)paTG)(gOfMX)Fw6kEeh~ zB>+G~=l4d>L&w~k-qqd3+Ro96-ow|`ir&h{&KdylSzgQ0&)gOzP<(2OH9-Lq&}a3X z<*m!{_V8N1vfR-!e#?4LHA`V0&813mdWs>I_jG?36@134I{t#(p?QJwCd>a=+-G|0 zz%)3hY31VX<}L;Y73sYttl06c4%J!X!BPg05rE4?70=#|crochmKfDzmeMp0kXSzO4QzaL+ZvBd5-bQZcdNYc@NAXjw#*#S^z9x-&7V{;8P5U!{934i! z9;mE;J|t|julTIKAjmECf?4h_EKu=0CvMAH2x<9(gT(48o(+t}&kjmu^63-^scPR&pm+LOy6UKmQHN4=z#vk^Sz!ZSvHhpJ^}7SSIR ziCDl=u78jQFmJ6!4)CGysb%zIDGRqKs&02| zo?BRKpN(SiT5DN3_NT_iEEl~=*Gb3ml!o7IL z{a)JtssY>_O1+3U7OhF=BqUVS&U?9b$32Xk&|e-#=Wp z5%~CkYHa*IGt$f2PC`4h7PEe#*?O(fhSUE@ckr-0E^}kvazK7cB}hfghVs;9EPREvG=*HC=n%F^M|C;t@*)TlEr|BWuLI zBkMf-(H@ZyAobJvdZ@wCn4e8gV2FPQrgM#e7GOsmbF*1_(y5}&SW!_nw^mc|85RUJ{v-yrU1U|RRXOQB_JlFwSKP>kZFsv$j@$AV}x5;dh%bf$(Ve1*-YZ*o_#rJWj` z$7a3v&wJ^aPwn~kU4Hh`5VNn==FE^ms7JwL<&nT4uhzK!40}imDWAE}TKYk^#F)Ms z=WFkeZJb|BgF@{!*2-4#WbkZ8n`8ZJm-7iV4{bK0g0uhF{!(l>=CC=a3&zJ8e2ru9O`e$;Sc&)j(9VfUFpVv+thi5f=Bec@p>N@DqMlAY| z6Elz5tOG%gD)@-wr7!gvH18U9S}6;a__r+fwg09)PxCP37SXvv;rvM^_kABu*f$t0 zvh@gWCp;2;+EzVQl|wD}6Rx#c8IID|`~KLHT8HB^eVo8$yNcNz1q*F2z)c`mf6;ud zf@4D$Lb>fbZL;RkF8sQUZm|$t=ZeqNos$06Eo;8iGJQnEoWYEhqlJ&;+c3dmtBi7O zO>TlV%K~0>!9bzEZVKK$`4eFtDMePl(2qh_pI1MKl@ix~Gmv7}zgb#(uYf;Do4eh= zHFRMxCJSEhtl;uWc(Abt{!m@|0X)f&0Kq0o3#7gk?`ULLs87T{tLCBJ%%jk*JaVfr zQQ=!$MS94SoaG8g&`V=v(nrXyncW+5W?thMe*4q`=LmVhJ?=g% zLKx&YJ=W)D$l+7aa7FR;`@Du#zx(tCsuVoeoa6AyiZd?UZmKrullt%H2|+$NvWyxa+Z@Nsl*(6tv;<-upWz(A1 zgn857X#L^ujQ>D0#Gti@0u5X2QlV zH`s_{@R@KYMUhg<))5VYMNAuP4Rcj#pv_adK0X2_i*FK9Cj?)r10v&EjEw7<-Z z=2c-1`;hV(3w~9$v$R`$dr%0 z;OkaXeJRx&|JN>@F@NUrt_98#?pe)nbY)d3S_S#i`LRE-^mn_7k3hugV}67C1k)3~ zysT4BCaJi!r{;iyQ-7*%zRxoYl}! Nnz${nI7>(7);R``TXo5r=LLC0$PO%e-WX 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 literal 0 HcmV?d00001 diff --git a/docs/sidebar.yml b/docs/sidebar.yml index 1b901d208ab7..c9831cad720f 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -15,7 +15,9 @@ sidebar: url: docs/usage/language-versions.html - title: cbt-projects url: docs/usage/cbt-projects.html - - title: Dottydoc + - title: Scala3doc + url: docs/usage/scala3doc + - title: Dottydoc [Legacy] url: docs/usage/dottydoc.html - title: Reference subsection: From dd2c092700f4b0a30ff1dbebe66bdf08f710e852 Mon Sep 17 00:00:00 2001 From: Aleksander Boruch-Gruszecki Date: Thu, 19 Nov 2020 23:05:29 +0100 Subject: [PATCH 05/11] Add docoumentation to new link syntax --- docs/docs/usage/scala3doc/docComments.md | 65 +++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/docs/docs/usage/scala3doc/docComments.md b/docs/docs/usage/scala3doc/docComments.md index c6fd4c6aad4c..9be9bec750ba 100644 --- a/docs/docs/usage/scala3doc/docComments.md +++ b/docs/docs/usage/scala3doc/docComments.md @@ -4,4 +4,67 @@ title: API Documentation # {{ page.title }} -Scala3doc main feature is to create API documentation based on [doc comments](https://docs.scala-lang.org/style/scaladoc.html) known from scaladoc as well well as new syntax introduced in Scala 3. \ No newline at end of file +Scala3doc main feature is to create API documentation based on [doc comments](https://docs.scala-lang.org/style/scaladoc.html) known from scaladoc as well well as new syntax introduced in Scala 3. + +## New syntax + +### Links + +The goal with the link syntax was to be as Scaladoc-compatible as possible, +while also making the links a bit more pleasant to type and read. +For the time being, Scala3doc mostly keeps Scaladoc's definition link syntax. We +did, however, implement some improvements to it: + +1. `package` can be used as a prefix to reference the enclosing package + Example: + ``` + package utils + class C { + def foo = "foo". + } + /** See also [[package.C]]. */ + class D { + def bar = "bar". + } + ``` + Links to the enclosing package in Scaladoc required mentioning the complete + package name. Using the `package` keyword (similarly to how one would use + `this` in expressions) helps make such links shorter. +1. `this` can be used as a prefix to reference the enclosing classlike + Example: + ``` + class C { + def foo = "foo" + /** This is not [[this.foo]], this is bar. */ + def bar = "bar" + } + ``` + Using a Scala keyword here helps make the links more familiar, as well as + helps the links survive class name changes. +1. Backticks can be used to escape identifiers + Example: + ``` + def `([.abusive.])` = ??? + /** TODO: Figure out what [[`([.abusive.])`]] is. */ + def foo = `([.abusive.])` + ``` + Scaladoc required backslash-escaping to reference such identifiers. Instead, + Scala3doc allows using the familiar Scala backtick quotation. + +### Why keep the Wiki syntax? + +There are a few reasons why we've kept the Wiki syntax for documentation links +instead of reusing the Markdown syntax. Those are: + +1. Nameless links in Markdown are ugly: `[](definition)` vs `[[definition]]` + By far, most links in documentation are nameless. It should be obvious how to + write them. +2. Local member lookup collides with URL fragments: `[](#field)` vs `[[#field]]` +3. Overload resolution collides with MD syntax: `[](meth(Int))` vs `[[meth(Int)]]` +4. Now that we have a parser for the link syntax, we can allow spaces inside (in + Scaladoc one needed to slash-escape those), but that doesn't get recognized + as a link in Markdown: `[](meth(Int, Float))` vs `[[meth(Int, Float)]]` + +None of these make it completely impossible to use the standard Markdown link +syntax, but they make it much more awkward and ugly than it needs to be. On top +of that, Markdown link syntax doesn't even save any characters. \ No newline at end of file From 1a382cf91d73f8eb4d40b51c7473ae3e18bddd76 Mon Sep 17 00:00:00 2001 From: Krzysztof Romanowski Date: Fri, 20 Nov 2020 00:59:02 +0100 Subject: [PATCH 06/11] URL in documentaion now matches files layout --- scala3doc/scala3-docs/index.html | 2 +- .../src/dotty/dokka/DottyDokkaPlugin.scala | 6 +-- .../dotty/dokka/site/StaticSiteContext.scala | 2 +- .../site/StaticSiteLocationProvider.scala | 41 ++++++++++++------- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/scala3doc/scala3-docs/index.html b/scala3doc/scala3-docs/index.html index d824cdadff87..46022b3068d6 100644 --- a/scala3doc/scala3-docs/index.html +++ b/scala3doc/scala3-docs/index.html @@ -20,7 +20,7 @@ diff --git a/scala3doc/src/dotty/dokka/DottyDokkaPlugin.scala b/scala3doc/src/dotty/dokka/DottyDokkaPlugin.scala index 08fa3456611f..d4c1c2823072 100644 --- a/scala3doc/src/dotty/dokka/DottyDokkaPlugin.scala +++ b/scala3doc/src/dotty/dokka/DottyDokkaPlugin.scala @@ -168,9 +168,9 @@ class DottyDokkaPlugin extends DokkaJavaPlugin: .overrideExtension(dokkaBase.getLocationProvider) ) - extension (ctx: DokkaContext): - def siteContext: Option[StaticSiteContext] = ctx.getConfiguration.asInstanceOf[DottyDokkaConfig].staticSiteContext - def args: Args = ctx.getConfiguration.asInstanceOf[DottyDokkaConfig].docConfiguration.args +extension (ctx: DokkaContext): + def siteContext: Option[StaticSiteContext] = ctx.getConfiguration.asInstanceOf[DottyDokkaConfig].staticSiteContext + def args: Args = ctx.getConfiguration.asInstanceOf[DottyDokkaConfig].docConfiguration.args // TODO (https://github.com/lampepfl/scala3doc/issues/232): remove once problem is fixed in Dokka extension [T] (builder: ExtensionBuilder[T]): diff --git a/scala3doc/src/dotty/dokka/site/StaticSiteContext.scala b/scala3doc/src/dotty/dokka/site/StaticSiteContext.scala index 74c43792f75f..bd6081c8c796 100644 --- a/scala3doc/src/dotty/dokka/site/StaticSiteContext.scala +++ b/scala3doc/src/dotty/dokka/site/StaticSiteContext.scala @@ -128,7 +128,7 @@ class StaticSiteContext(val root: File, sourceSets: Set[SourceSetWrapper], args: case Sidebar.Category(title, nested) => // Add support for index.html/index.md files! - val fakeFile = new File(root, title) + val fakeFile = new File(new File(root, "docs"), title) LoadedTemplate(emptyTemplate(fakeFile, title), nested.map(loadSidebarContent), fakeFile) private def loadAllFiles() = diff --git a/scala3doc/src/dotty/dokka/site/StaticSiteLocationProvider.scala b/scala3doc/src/dotty/dokka/site/StaticSiteLocationProvider.scala index d66d58f2e936..4619c8c290e0 100644 --- a/scala3doc/src/dotty/dokka/site/StaticSiteLocationProvider.scala +++ b/scala3doc/src/dotty/dokka/site/StaticSiteLocationProvider.scala @@ -20,29 +20,40 @@ class StaticSiteLocationProvider(ctx: DokkaContext, pageNode: RootPageNode) private def updatePageEntry(page: PageNode, jpath: JList[String]): JList[String] = page match case page: StaticPageNode => - if (page.getDri.contains(docsRootDRI)) JList("index") - else { - val path = jpath.asScala.toList - val start = if (path.head == "--root--") List("docs") else path.take(1) - // Dokka has a bug in location provider that does not properly handles relative paths for leaf nodes - // This forces us to not change default paths on non-leaf nodes - val newName = if page.getChildren.size() > 0 then path.last else - val pageName = page.template.file.getName - val dotIndex = pageName.lastIndexOf('.') - if (dotIndex < 0) pageName else pageName.substring(0, dotIndex) - - println(s"Using $newName for ${page.template.file} orignally: $path") - - (start ++ path.drop(1).dropRight(1) ++ List(newName)).asJava + ctx.siteContext.fold(jpath) { context => + val rawFilePath = context.root.toPath.relativize(page.template.file.toPath) + val pageName = page.template.file.getName + val dotIndex = pageName.lastIndexOf('.') + val newPath = + if (dotIndex < 0) rawFilePath.resolve("index") + else rawFilePath.resolveSibling(pageName.substring(0, dotIndex)) + + newPath.iterator.asScala.map(_.toString).toList.asJava } + case page: ContentPage if page.getDri.contains(docsDRI) => - JList("docs") + JList("docs", "index") case page: ContentPage if page.getDri.contains(apiPageDRI) => JList("api", "index") case _ if jpath.size() > 1 && jpath.get(0) == "--root--" && jpath.get(1) == "-a-p-i" => (List("api") ++ jpath.asScala.drop(2)).asJava + + case _: org.jetbrains.dokka.pages.ModulePage if ctx.siteContext.isEmpty => + JList("index") case _ => jpath override val getPathsIndex: JMap[PageNode, JList[String]] = super.getPathsIndex.asScala.mapValuesInPlace(updatePageEntry).asJava + + + override def pathTo(node: PageNode, context: PageNode): String = + val nodePaths = getPathsIndex.get(node).asScala + val contextPaths = Option(context).fold(Nil)(getPathsIndex.get(_).asScala.dropRight(1)) + val commonPaths = nodePaths.zip(contextPaths).takeWhile{ case (a, b) => a == b }.size + + val contextPath = contextPaths.drop(commonPaths).map(_ => "..") + val nodePath = nodePaths.drop(commonPaths) match + case l if l.isEmpty => Seq("index") + case l => l + (contextPath ++ nodePath).mkString("/") \ No newline at end of file From 9402c5b980d966225190b52a1145d8bbc6901fe0 Mon Sep 17 00:00:00 2001 From: Krzysztof Romanowski Date: Fri, 20 Nov 2020 10:46:25 +0100 Subject: [PATCH 07/11] Remove duplication of the same page --- scala3doc/src/dotty/dokka/site/LoadedTemplate.scala | 2 +- .../src/dotty/dokka/site/StaticSiteContext.scala | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/scala3doc/src/dotty/dokka/site/LoadedTemplate.scala b/scala3doc/src/dotty/dokka/site/LoadedTemplate.scala index bd5fa05ac43c..c6c104a52373 100644 --- a/scala3doc/src/dotty/dokka/site/LoadedTemplate.scala +++ b/scala3doc/src/dotty/dokka/site/LoadedTemplate.scala @@ -31,7 +31,7 @@ case class LoadedTemplate(templateFile: TemplateFile, children: List[LoadedTempl "..." def lazyTemplateProperties(ctx: StaticSiteContext): JMap[String, Object] = new java.util.AbstractMap[String, Object](): - def entrySet(): JSet[JMapEntry[String, Object]] = + lazy val entrySet: JSet[JMapEntry[String, Object]] = val site = templateFile.settings.getOrElse("page", Map.empty).asInstanceOf[Map[String, Object]] site.asJava.entrySet() ++ JSet( LazyEntry("url", () => ctx.relativePath(LoadedTemplate.this).toString), diff --git a/scala3doc/src/dotty/dokka/site/StaticSiteContext.scala b/scala3doc/src/dotty/dokka/site/StaticSiteContext.scala index bd6081c8c796..66f6c4945bc8 100644 --- a/scala3doc/src/dotty/dokka/site/StaticSiteContext.scala +++ b/scala3doc/src/dotty/dokka/site/StaticSiteContext.scala @@ -56,15 +56,16 @@ class StaticSiteContext(val root: File, sourceSets: Set[SourceSetWrapper], args: if !Files.exists(docsPath) then Nil else Files.walk(docsPath, FileVisitOption.FOLLOW_LINKS).iterator().asScala.toList - val orphanedFiles = allPaths.filterNot(mainFiles.contains).filter { p => + val orphanedFiles = allPaths.filterNot { p => + def name = p.getFileName.toString + def isMain = name == "index.html" || name == "index.md" + mainFiles.contains(p) || (isMain && mainFiles.contains(p.getParent)) + }.filter { p => val name = p.getFileName.toString - def isSupported = name.endsWith(".md") || name.endsWith(".html") - def notIndex = name == "index.md" || name == "index.html" - isSupported && notIndex + name.endsWith(".md") || name.endsWith(".html") } val orphanedTemplates = orphanedFiles.flatMap(p => loadTemplate(p.toFile, isBlog = false)) - mainPages ++ orphanedTemplates.map(templateToPage) } From b0fd8c8e4d933918826818a961f30fa6830a143b Mon Sep 17 00:00:00 2001 From: Krzysztof Romanowski Date: Fri, 20 Nov 2020 11:17:14 +0100 Subject: [PATCH 08/11] Fix typs and wording in scala3documentation --- docs/docs/usage/scala3doc/blog.md | 2 +- docs/docs/usage/scala3doc/index.md | 8 +++++--- docs/docs/usage/scala3doc/specificTags.md | 2 +- docs/docs/usage/scala3doc/staticSite.md | 12 ++++++------ 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/docs/usage/scala3doc/blog.md b/docs/docs/usage/scala3doc/blog.md index 2d13ca155561..690c30c43df9 100644 --- a/docs/docs/usage/scala3doc/blog.md +++ b/docs/docs/usage/scala3doc/blog.md @@ -4,4 +4,4 @@ title: Build-in blog # {{page.title}} -Scala3doc is capable to include blogposts. For now we support only simple blogposts but in future we plan to include more advanced features like tags. \ No newline at end of file +Scala3doc is able to include a simple blog in your documentation. For now it provides only basic features in future we plan to include more advanced features like tagging or author pages. \ No newline at end of file diff --git a/docs/docs/usage/scala3doc/index.md b/docs/docs/usage/scala3doc/index.md index 4af462a9c14d..d8dd1d4451b7 100644 --- a/docs/docs/usage/scala3doc/index.md +++ b/docs/docs/usage/scala3doc/index.md @@ -4,8 +4,10 @@ title: Scala3doc ![Scala3doc logo](/images/scala3doc-logo.png) -Scala3doc is a doctool dedicated to work with Scala 3.0. Beside basic features similar to `javadoc` or `scaladoc`. As you probably guessed, this -whole site was created using scala3doc. +Scala3doc is tool to generate documentation for your Scala 3 projects. It provies similar features to `javadoc` or `scaladoc` as well as `jekyll` or `docusaurus`. + +As you probably guessed, this whole site was created using scala3doc. + {% for post in site.posts %} ## [{{ post.title }}](/{{ post.url }}) @@ -20,5 +22,5 @@ whole site was created using scala3doc. We would love to have your feedback on what you think would be good in order to render the documentation you want! Perhaps you would like to render method -definitions or members? Let us know by filing +definitions or members? Do you want to have runnable code samples? Let us know by filing [issues](https://github.com/lampepfl/dotty/issues/new)! \ No newline at end of file diff --git a/docs/docs/usage/scala3doc/specificTags.md b/docs/docs/usage/scala3doc/specificTags.md index f684ff5da49c..8965b0f83359 100644 --- a/docs/docs/usage/scala3doc/specificTags.md +++ b/docs/docs/usage/scala3doc/specificTags.md @@ -4,7 +4,7 @@ title: Dottydoc Specific Tags and Behavior # {{page.title}} -Scala3doc extemds markdown with some unique behaviours such as linking to API. This can be used from within static documentation and blogpost to provide blend-in content. +Scala3doc extends markdown with some unique behaviors such as linking to API. This can be used from within static documentation and blog posts to provide blend-in content. ## Linking to API diff --git a/docs/docs/usage/scala3doc/staticSite.md b/docs/docs/usage/scala3doc/staticSite.md index 29b04f167469..815a77563354 100644 --- a/docs/docs/usage/scala3doc/staticSite.md +++ b/docs/docs/usage/scala3doc/staticSite.md @@ -4,8 +4,8 @@ title: Static docucmentation # {{ page.title}} -Scala3doc has similar functionalites to [Jekyll](http://jekyllrb.com/) to allow users to documentation in form of static sit alongside your APIs. Moreover having a combined tool allows provide reach interaction between those to such as linking thus allowing the two to -blend naturally. +Scala3doc is able to generate static sites, known from [Jekyll](http://jekyllrb.com/) or [Docusaurus](https://docusaurus.io/). +Having a combined tool allows to provide interaction between static documentation and API thus allowing the two to blend naturally. 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, @@ -42,13 +42,13 @@ is parsed and put into the `page` variable available in templates via Liquid. Scala3doc uses some predefied properties to controls some aspect of page. -Predefiend properties: +Predefined properties: - **title** provide page title that will be used in navigation and html metadata. - **extraCss** additional `.css` files that will be included in this page. Paths should be relative to documentation root. **This setting is not exported to template engine** - **extraJs** additional `.js` files that will be included in this page. Paths should be relative to documentation root. **This setting is not exported to template engine** - - **hasFrame** when set to `false` page will not include default layout (navigation, breadcrumbs etc.) but only token html wrapper to provide metadata and resources (js and css files) -- **layout** - predefined layout to use, see below + - **hasFrame** when set to `false` page will not include default layout (navigation, breadcrumbs etc.) but only token html wrapper to provide metadata and resources (js and css files). **This setting is not exported to template engine** +- **layout** - predefined layout to use, see below. **This setting is not exported to template engine** ## Using existing Templates and Layouts @@ -114,7 +114,7 @@ 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 however it accepts both files and directories and latter can be used to provide deeper structures. -The items which have the `subsection` does not accepts `url` section. +The items which have on the `subsection` level does not accepts `url`. ``` ├── blog From 25f5e088710589da98ce6d7dfc519466ba2529fb Mon Sep 17 00:00:00 2001 From: Aleksander Boruch-Gruszecki Date: Fri, 20 Nov 2020 12:42:26 +0100 Subject: [PATCH 09/11] Scala3doc: add documentation for API links --- docs/docs/usage/scala3doc/docComments.md | 44 ++++++++++++++++----- docs/docs/usage/scala3doc/specificTags.md | 28 ++++--------- scala3doc/src/dotty/dokka/site/common.scala | 1 + 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/docs/docs/usage/scala3doc/docComments.md b/docs/docs/usage/scala3doc/docComments.md index 9be9bec750ba..2336e41aa9b7 100644 --- a/docs/docs/usage/scala3doc/docComments.md +++ b/docs/docs/usage/scala3doc/docComments.md @@ -4,16 +4,42 @@ title: API Documentation # {{ page.title }} -Scala3doc main feature is to create API documentation based on [doc comments](https://docs.scala-lang.org/style/scaladoc.html) known from scaladoc as well well as new syntax introduced in Scala 3. +Scala3doc's main feature is creating API documentation from code comments. -## New syntax +By default, the code comments are understood as Markdown, though we also support +Scaladoc's old [Wiki syntax](https://docs.scala-lang.org/style/scaladoc.html). -### Links +## Syntax -The goal with the link syntax was to be as Scaladoc-compatible as possible, -while also making the links a bit more pleasant to type and read. -For the time being, Scala3doc mostly keeps Scaladoc's definition link syntax. We -did, however, implement some improvements to it: +### Definition links + +Our definition link syntax is quite close to Scaladoc's syntax, though we have made some +quality-of-life improvements. + +#### Basic syntax + +A definition link looks as follows: `[[scala.collection.immutable.List]]`. + +Which is to say, a definition link is a sequence of identifiers separated by +`.`. The identifiers can be separated with `#` as well for Scaladoc compatibility. + +By default, an identifier `id` references the first (in source order) entity +named `id`. An identifier can end with `$`, which forces it to refer to a value +(an object, a value, a given); an identifier can also end with `!`, which forces +it to refer to a type (a class, a type alias, a type member). + +The links are resolved relative to the current location in source. That is, when +documenting a class, the links are relative to the entity enclosing the class (a +package, a class, an object); the same applies to documenting definitions. + +Special characters in links can be backslash-escaped, which makes them part of +identifiers instead. For example, `` [[scala.collection.immutable\.List]] `` +references the class named `` `immutable.List` `` in package `scala.collection`. + +#### New syntax + +We have extended Scaladoc definition links to make them a bit more pleasant to +write and read in source. The new syntax features are: 1. `package` can be used as a prefix to reference the enclosing package Example: @@ -51,7 +77,7 @@ did, however, implement some improvements to it: Scaladoc required backslash-escaping to reference such identifiers. Instead, Scala3doc allows using the familiar Scala backtick quotation. -### Why keep the Wiki syntax? +#### Why keep the Wiki syntax for links? There are a few reasons why we've kept the Wiki syntax for documentation links instead of reusing the Markdown syntax. Those are: @@ -67,4 +93,4 @@ instead of reusing the Markdown syntax. Those are: None of these make it completely impossible to use the standard Markdown link syntax, but they make it much more awkward and ugly than it needs to be. On top -of that, Markdown link syntax doesn't even save any characters. \ No newline at end of file +of that, Markdown link syntax doesn't even save any characters. diff --git a/docs/docs/usage/scala3doc/specificTags.md b/docs/docs/usage/scala3doc/specificTags.md index 8965b0f83359..9429a0c333e7 100644 --- a/docs/docs/usage/scala3doc/specificTags.md +++ b/docs/docs/usage/scala3doc/specificTags.md @@ -1,29 +1,15 @@ --- -title: Dottydoc Specific Tags and Behavior +title: Scala3doc-specific Tags and Features --- # {{page.title}} -Scala3doc extends markdown with some unique behaviors such as linking to API. This can be used from within static documentation and blog posts to provide blend-in content. +Scala3doc extends Markdown with additional features, such as linking +to API definitions. This can be used from within static documentation and blog +posts to provide blend-in content. ## 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) -``` - -Scala3doc denotes objects by ending their names in "$". To select `List.range` -you'd therefore write: - -```markdown -[List.range](scala.collection.immutable.List$.range) -``` \ No newline at end of file +Scala3doc allows linking to API documentation with Wiki-style links. Linking to +`scala.collection.immutable.List` is as simple as +`[[scala.collection.immutable.List]]`. For more information on the exact syntax, see [doc comment documentation](./docComments.html#definition-links). diff --git a/scala3doc/src/dotty/dokka/site/common.scala b/scala3doc/src/dotty/dokka/site/common.scala index 9f93d75c51a6..6f2936d8959e 100644 --- a/scala3doc/src/dotty/dokka/site/common.scala +++ b/scala3doc/src/dotty/dokka/site/common.scala @@ -28,6 +28,7 @@ val defaultMarkdownOptions: DataHolder = .set(AnchorLinkExtension.ANCHORLINKS_WRAP_TEXT, false) .set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor") .set(EmojiExtension.ROOT_IMAGE_PATH, "https://github.global.ssl.fastly.net/images/icons/emoji/") + .set(WikiLinkExtension.LINK_ESCAPE_CHARS, "") .set(Parser.EXTENSIONS, java.util.Arrays.asList( TablesExtension.create(), TaskListExtension.create(), From d3698ee2b71e407e23abf63adab07569e3eab1d8 Mon Sep 17 00:00:00 2001 From: Aleksander Boruch-Gruszecki Date: Fri, 20 Nov 2020 12:48:06 +0100 Subject: [PATCH 10/11] Scala3doc: improve docs --- docs/docs/usage/scala3doc/blog.md | 6 ++++-- docs/docs/usage/scala3doc/index.md | 6 +++--- docs/docs/usage/scala3doc/staticSite.md | 20 ++++++++++---------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/docs/docs/usage/scala3doc/blog.md b/docs/docs/usage/scala3doc/blog.md index 690c30c43df9..af257074dce9 100644 --- a/docs/docs/usage/scala3doc/blog.md +++ b/docs/docs/usage/scala3doc/blog.md @@ -1,7 +1,9 @@ --- -title: Build-in blog +title: Built-in blog --- # {{page.title}} -Scala3doc is able to include a simple blog in your documentation. For now it provides only basic features in future we plan to include more advanced features like tagging or author pages. \ No newline at end of file +Scala3doc allows you to include a simple blog in your documentation. For now, it +provides only basic features. In the future, we plan to include more advanced +features like tagging or author pages. diff --git a/docs/docs/usage/scala3doc/index.md b/docs/docs/usage/scala3doc/index.md index d8dd1d4451b7..2603ebf76256 100644 --- a/docs/docs/usage/scala3doc/index.md +++ b/docs/docs/usage/scala3doc/index.md @@ -6,7 +6,7 @@ title: Scala3doc Scala3doc is tool to generate documentation for your Scala 3 projects. It provies similar features to `javadoc` or `scaladoc` as well as `jekyll` or `docusaurus`. -As you probably guessed, this whole site was created using scala3doc. +As you probably have guessed, this whole site was created using Scala3doc. {% for post in site.posts %} @@ -22,5 +22,5 @@ As you probably guessed, this whole site was created using scala3doc. We would love to have your feedback on what you think would be good in order to render the documentation you want! Perhaps you would like to render method -definitions or members? Do you want to have runnable code samples? Let us know by filing -[issues](https://github.com/lampepfl/dotty/issues/new)! \ No newline at end of file +definitions or members? Do you want to have runnable code snippets? Let us know +by filing [issues](https://github.com/lampepfl/dotty/issues/new)! diff --git a/docs/docs/usage/scala3doc/staticSite.md b/docs/docs/usage/scala3doc/staticSite.md index 815a77563354..66d9521cd831 100644 --- a/docs/docs/usage/scala3doc/staticSite.md +++ b/docs/docs/usage/scala3doc/staticSite.md @@ -5,10 +5,10 @@ title: Static docucmentation # {{ page.title}} Scala3doc is able to generate static sites, known from [Jekyll](http://jekyllrb.com/) or [Docusaurus](https://docusaurus.io/). -Having a combined tool allows to provide interaction between static documentation and API thus allowing the two to blend naturally. +Having a combined tool allows to provide interaction between static documentation and API, thus allowing the two to blend naturally. 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, +layout of the site and all files placed there will be either considered static, or processed for template expansion. The files that are considered for template expansion must end in `*.{html,md}` @@ -22,7 +22,7 @@ A simple "hello world" site could look something like this: └── index.html ``` -This will give you a site with the following files in genrated documentation: +This will give you a site with the following files in generated documentation: ``` index.html @@ -40,20 +40,20 @@ documentation. In Scala3doc, all templates can contain YAML front-matter. The front-matter is parsed and put into the `page` variable available in templates via Liquid. -Scala3doc uses some predefied properties to controls some aspect of page. +Scala3doc uses some predefined properties to controls some aspect of page. Predefined properties: - **title** provide page title that will be used in navigation and html metadata. - - **extraCss** additional `.css` files that will be included in this page. Paths should be relative to documentation root. **This setting is not exported to template engine** - - **extraJs** additional `.js` files that will be included in this page. Paths should be relative to documentation root. **This setting is not exported to template engine** - - **hasFrame** when set to `false` page will not include default layout (navigation, breadcrumbs etc.) but only token html wrapper to provide metadata and resources (js and css files). **This setting is not exported to template engine** -- **layout** - predefined layout to use, see below. **This setting is not exported to template engine** + - **extraCss** additional `.css` files that will be included in this page. Paths should be relative to documentation root. **This setting is not exported to template engine.** + - **extraJs** additional `.js` files that will be included in this page. Paths should be relative to documentation root. **This setting is not exported to template engine.** + - **hasFrame** when set to `false` page will not include default layout (navigation, breadcrumbs etc.) but only token html wrapper to provide metadata and resources (js and css files). **This setting is not exported to template engine.** +- **layout** - predefined layout to use, see below. **This setting is not exported to template engine.** ## Using existing Templates and Layouts -To perform template expansion, Dottydoc looks at `layout` in the front-matter. +To perform template expansion, Dottydoc looks at the `layout` field in the front-matter. Here's a simple example of the templating system in action, `index.html`: ```html @@ -94,7 +94,7 @@ Layouts must be placed in a `_layouts` directory in the site root: Sidebar ======= -Scala3doc by default use layout of files in `docs` directory to create table of content. There is also ability to override it by providing a `sidebar.yml` file in the site root: +Scala3doc by default uses layout of files in `docs` directory to create table of content. There is also ability to override it by providing a `sidebar.yml` file in the site root: ```yaml sidebar: From 93a87b00e0a0377794a436c89ee26aee089ca127 Mon Sep 17 00:00:00 2001 From: Aleksander Boruch-Gruszecki Date: Mon, 23 Nov 2020 14:07:49 +0100 Subject: [PATCH 11/11] Docs: don't make unnecessary claims --- docs/docs/usage/scala3doc/docComments.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/docs/usage/scala3doc/docComments.md b/docs/docs/usage/scala3doc/docComments.md index 2336e41aa9b7..cd33cf3000e1 100644 --- a/docs/docs/usage/scala3doc/docComments.md +++ b/docs/docs/usage/scala3doc/docComments.md @@ -39,7 +39,8 @@ references the class named `` `immutable.List` `` in package `scala.collection`. #### New syntax We have extended Scaladoc definition links to make them a bit more pleasant to -write and read in source. The new syntax features are: +write and read in source. The aim was also to bring the link and Scala syntax +closer together. The new features are: 1. `package` can be used as a prefix to reference the enclosing package Example: @@ -53,9 +54,8 @@ write and read in source. The new syntax features are: def bar = "bar". } ``` - Links to the enclosing package in Scaladoc required mentioning the complete - package name. Using the `package` keyword (similarly to how one would use - `this` in expressions) helps make such links shorter. + The `package` keyword helps make links to the enclosing package shorter + and a bit more resistant to name refactorings. 1. `this` can be used as a prefix to reference the enclosing classlike Example: ```