Skip to content

Commit 66eee84

Browse files
authored
Merge pull request #10237 from romanowski/scala3doc/fixes-in-scaladoc
Scala3doc/fixes in scaladoc
2 parents 6485049 + 1bddfc1 commit 66eee84

File tree

11 files changed

+1209
-78
lines changed

11 files changed

+1209
-78
lines changed

project/Build.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,6 +1480,7 @@ object Build {
14801480
"org.jetbrains.kotlinx" % "kotlinx-html-jvm" % "0.7.2", // Needs update when dokka version changes
14811481
"com.vladsch.flexmark" % "flexmark-all" % "0.42.12",
14821482
"nl.big-o" % "liqp" % "0.6.7",
1483+
"org.jsoup" % "jsoup" % "1.13.1", // Needed to process .html files for static site
14831484
"args4j" % "args4j" % "2.33",
14841485
Dependencies.`jackson-dataformat-yaml`,
14851486

scala3doc/resources/dotty_res/hljs/highlight.pack.js

Lines changed: 1060 additions & 2 deletions
Large diffs are not rendered by default.

scala3doc/scala3-docs/css/dottydoc.css

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,6 @@ pre {
192192
border: 1px solid rgba(0, 0, 0, 0.1);
193193
}
194194

195-
pre > code {
196-
display: block;
197-
padding: 0.5rem;
198-
overflow-x: auto;
199-
background: transparent;
200-
}
201-
202195
/* admonitions */
203196
blockquote {
204197
padding: 0 1em;

scala3doc/src/dotty/dokka/site/PartiallyRenderedContent.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ package site
44
import org.jetbrains.dokka.model.DisplaySourceSet
55
import org.jetbrains.dokka.model.properties.PropertyContainer
66
import org.jetbrains.dokka.pages.{ContentNode, DCI, Style}
7+
import org.jetbrains.dokka.base.resolvers.local.LocationProvider
8+
import com.vladsch.flexmark.convert.html.FlexmarkHtmlParser
9+
import org.jsoup.Jsoup
710

811
case class PartiallyRenderedContent(
912
template: TemplateFile,
@@ -23,3 +26,8 @@ case class PartiallyRenderedContent(
2326
copy(getSourceSets = sourceSets)
2427

2528
lazy val resolved = template.resolveToHtml(context)
29+
30+
def procsesHtml(linkTo: String => String): String =
31+
val document = Jsoup.parse(resolved.code)
32+
document.select("a").forEach(element => element.attr("href", linkTo(element.attr("href"))))// forrach does not work here
33+
document.outerHtml()

scala3doc/src/dotty/dokka/site/StaticPageNode.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@ import org.jetbrains.dokka.model.Documentable
1010
import org.jetbrains.dokka.pages._
1111
import org.jetbrains.dokka.transformers.pages.PageTransformer
1212

13-
case class LoadedTemplate(templateFile: TemplateFile, children: List[LoadedTemplate], file: File) {
14-
def relativePath(root: File): String =
15-
root.toPath().relativize(file.toPath()).toString().replace(File.separatorChar, '.')
16-
}
13+
case class LoadedTemplate(templateFile: TemplateFile, children: List[LoadedTemplate], file: File)
1714

1815
case class StaticPageNode(
1916
template: TemplateFile,

scala3doc/src/dotty/dokka/site/StaticSiteContext.scala

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package site
33

44
import java.io.File
55
import java.nio.file.Files
6-
6+
import java.nio.file.FileVisitOption
7+
import java.nio.file.Path
8+
import java.nio.file.Paths
79

810
import org.jetbrains.dokka.base.parsers.MarkdownParser
911
import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter
@@ -15,14 +17,16 @@ import org.jetbrains.dokka.pages.{ContentKind, ContentNode, DCI, PageNode}
1517
import org.jetbrains.dokka.plugability.DokkaContext
1618
import org.jetbrains.dokka.pages.Style
1719
import org.jetbrains.dokka.model.DisplaySourceSet
20+
import util.Try
1821

1922
import scala.collection.JavaConverters._
2023

2124
class StaticSiteContext(val root: File, sourceSets: Set[SourceSetWrapper]):
2225

2326
def indexPage():Option[StaticPageNode] =
2427
val files = List(new File(root, "index.html"), new File(root, "index.md")).filter { _.exists() }
25-
if (files.size > 1) println(s"ERROR: Multiple root index pages found: ${files.map(_.getAbsolutePath)}") // TODO (#14): provide proper error handling
28+
// TODO (https://github.com/lampepfl/scala3doc/issues/238): provide proper error handling
29+
if (files.size > 1) println(s"ERROR: Multiple root index pages found: ${files.map(_.getAbsolutePath)}")
2630
files.flatMap(loadTemplate(_, isBlog = false)).headOption.map(templateToPage)
2731

2832
lazy val layouts: Map[String, TemplateFile] =
@@ -37,7 +41,27 @@ class StaticSiteContext(val root: File, sourceSets: Set[SourceSetWrapper]):
3741

3842
lazy val templates: Seq[LoadedTemplate] = sideBarConfig.fold(loadAllFiles())(_.map(loadSidebarContent))
3943

40-
lazy val pages = templates.map(templateToPage)
44+
lazy val mainPages: Seq[StaticPageNode] = templates.map(templateToPage)
45+
46+
lazy val allPages: Seq[StaticPageNode] = sideBarConfig.fold(mainPages){ sidebar =>
47+
def flattenPages(p: StaticPageNode): Set[Path] =
48+
Set(p.template.file.toPath) ++ p.getChildren.asScala.collect { case p: StaticPageNode => flattenPages(p) }.flatten
49+
50+
val mainFiles = mainPages.toSet.flatMap(flattenPages)
51+
val docsPath = root.toPath.resolve("docs")
52+
val allPaths =
53+
if !Files.exists(docsPath) then Nil
54+
else Files.walk(docsPath, FileVisitOption.FOLLOW_LINKS).iterator().asScala.toList
55+
56+
val orphanedFiles = allPaths.filterNot(mainFiles.contains).filter { p =>
57+
val name = p.getFileName.toString
58+
name.endsWith(".md") || name.endsWith(".html")
59+
}
60+
61+
val orphanedTemplates = orphanedFiles.flatMap(p => loadTemplate(p.toFile, isBlog = false))
62+
63+
mainPages ++ orphanedTemplates.map(templateToPage)
64+
}
4165

4266
private def isValidTemplate(file: File): Boolean =
4367
(file.isDirectory && !file.getName.startsWith("_")) ||
@@ -52,7 +76,8 @@ class StaticSiteContext(val root: File, sourceSets: Set[SourceSetWrapper]):
5276
val allFiles = topLevelFiles.filter(_.isDirectory).flatMap(_.listFiles())
5377
val (indexes, children) = allFiles.flatMap(loadTemplate(_)).partition(_.templateFile.isIndexPage())
5478
if (indexes.size > 1)
55-
println(s"ERROR: Multiple index pages for $from found in ${indexes.map(_.file)}") // TODO (#14): provide proper error handling
79+
// TODO (https://github.com/lampepfl/scala3doc/issues/238): provide proper error handling
80+
println(s"ERROR: Multiple index pages for $from found in ${indexes.map(_.file)}")
5681

5782
def loadIndexPage(): TemplateFile =
5883
val indexFiles = from.listFiles { file =>file.getName == "index.md" || file.getName == "index.html" }
@@ -68,7 +93,8 @@ class StaticSiteContext(val root: File, sourceSets: Set[SourceSetWrapper]):
6893
Some(LoadedTemplate(templateFile, children.toList, from))
6994
catch
7095
case e: RuntimeException =>
71-
e.printStackTrace() // TODO (#14): provide proper error handling
96+
// TODO (https://github.com/lampepfl/scala3doc/issues/238): provide proper error handling
97+
e.printStackTrace()
7298
None
7399

74100
def asContent(doctag: DocTag, dri: DRI) = new DocTagToContentConverter().buildContent(
@@ -83,10 +109,11 @@ class StaticSiteContext(val root: File, sourceSets: Set[SourceSetWrapper]):
83109
case Sidebar.Page(title, url) =>
84110
val isBlog = title == "Blog"
85111
val path = if isBlog then "blog" else url.stripSuffix(".html") + ".md"
86-
val file = root.toPath.resolve(path) // Add support for.html files!
112+
val file = root.toPath.resolve(path) // Add support for .html files!
87113
val LoadedTemplate(template, children, tFile) = loadTemplate(file.toFile, isBlog).get // Add proper logging if file does not exisits
88114
LoadedTemplate(template.copy(settings = template.settings + ("title" -> List(title))), children, tFile)
89115
case Sidebar.Category(title, nested) =>
116+
// Add support for index.html/index.md files!
90117
val fakeFile = new File(root, title)
91118
LoadedTemplate(emptyTemplate(fakeFile), nested.map(loadSidebarContent), fakeFile)
92119

@@ -95,9 +122,15 @@ class StaticSiteContext(val root: File, sourceSets: Set[SourceSetWrapper]):
95122
dir("docs").flatMap(_.listFiles()).flatMap(loadTemplate(_, isBlog = false))
96123
++ dir("blog").flatMap(loadTemplate(_, isBlog = true))
97124

125+
def driForLink(template: TemplateFile, link: String): Try[DRI] = Try(driFor(
126+
if link.startsWith("/") then root.toPath.resolve(link.drop(1))
127+
else template.file.toPath.getParent().resolve(link)
128+
))
129+
130+
private def driFor(dest: Path): DRI = mkDRI(s"_.${root.toPath.relativize(dest)}")
131+
98132
def templateToPage(myTemplate: LoadedTemplate): StaticPageNode =
99-
def pathToDRI(path: String) = mkDRI(s"_.$path")
100-
val dri = pathToDRI(myTemplate.relativePath(root))
133+
val dri = driFor(myTemplate.file.toPath)
101134
val content = new PartiallyRenderedContent(
102135
myTemplate.templateFile,
103136
this,

scala3doc/src/dotty/dokka/site/processors.scala

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package site
33

44
import java.io.File
55
import java.nio.file.Files
6+
import java.nio.file.FileVisitOption
67

78
import org.jetbrains.dokka.base.renderers.html.{NavigationNode, NavigationPage}
89
import org.jetbrains.dokka.links.DRI
@@ -25,18 +26,20 @@ class SiteResourceManager(ctx: Option[StaticSiteContext]) extends BaseStaticSite
2526
}.toSet
2627

2728
override def transform(input: RootPageNode, ctx: StaticSiteContext): RootPageNode =
28-
val imgPath = ctx.root.toPath().resolve("images")
29+
val rootPath = ctx.root.toPath
30+
val imgPath = rootPath.resolve("images")
2931
val images =
3032
if !Files.exists(imgPath) then Nil
3133
else
32-
val stream = Files.walk(imgPath)filter(p => Files.isRegularFile(p) && p.getFileName().toString().endsWith(".svg"))
33-
stream.iterator().asScala.toList.map(_.toString)
34+
val allPaths = Files.walk(imgPath, FileVisitOption.FOLLOW_LINKS)
35+
val files = allPaths.filter(Files.isRegularFile(_)).iterator().asScala
36+
files.map(p => rootPath.relativize(p).toString).toList
3437

35-
val resources = listResources(input.getChildren.asScala.toList) ++ images
38+
val resources = images ++ listResources(input.getChildren.asScala.toList)
3639
val resourcePages = resources.map { path =>
37-
val content = Files.readAllLines(ctx.root.toPath.resolve(path)).asScala.mkString("\n")
38-
new RendererSpecificResourcePage(path, JList(), new RenderingStrategy.Write(content))
39-
}.toList
40+
val strategy = new RenderingStrategy.Copy(rootPath.resolve(path).toString)
41+
new RendererSpecificResourcePage(path, JList(), strategy)
42+
}
4043

4144
val modified = input.transformContentPagesTree {
4245
case it: StaticPageNode =>
@@ -90,8 +93,8 @@ class SitePagesCreator(ctx: Option[StaticSiteContext]) extends BaseStaticSitePro
9093
override def transform(input: RootPageNode, ctx: StaticSiteContext): RootPageNode =
9194
val (contentPage, others) = input.getChildren.asScala.toList.partition { _.isInstanceOf[ContentPage] }
9295
val modifiedModuleRoot = processRootPage(input, contentPage)
93-
val (indexes, children) = ctx.pages.partition(_.template.isIndexPage())
94-
// TODO (#14): provide proper error handling
96+
val (indexes, children) = ctx.allPages.partition(_.template.isIndexPage())
97+
// TODO (https://github.com/lampepfl/scala3doc/issues/238): provide proper error handling
9598
if (indexes.size > 1) println("ERROR: Multiple index pages found $indexes}")
9699

97100
val rootContent = indexes.headOption.fold(ctx.asContent(Text(), mkDRI(extra = "root_content")).get(0))(_.getContent)
@@ -131,7 +134,7 @@ class RootIndexPageCreator(ctx: Option[StaticSiteContext]) extends BaseStaticSit
131134
input.getName,
132135
docsRootDRI,
133136
root.getSourceSets,
134-
(ctx.pages.map(toNavigationNode) ++ api).asJava
137+
(ctx.mainPages.map(toNavigationNode) ++ api).asJava
135138
)
136139
)
137140
}

scala3doc/src/dotty/dokka/site/templates.scala

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
package dotty.dokka.site
1+
package dotty.dokka
2+
package site
23

34
import java.io.File
45
import java.nio.file.Files
@@ -22,7 +23,6 @@ case class RenderingContext(
2223
properties: Map[String, Object],
2324
layouts: Map[String, TemplateFile] = Map(),
2425
resolving: Set[String] = Set(),
25-
markdownOptions: DataHolder = defaultMarkdownOptions,
2626
resources: List[String] = Nil
2727
):
2828

@@ -70,7 +70,9 @@ case class TemplateFile(
7070

7171
def isIndexPage() = file.isFile && (file.getName == "index.md" || file.getName == "index.html")
7272

73-
def resolveToHtml(ctx: StaticSiteContext): ResolvedPage = resolveInner(RenderingContext(Map(), ctx.layouts))
73+
def resolveToHtml(ctx: StaticSiteContext): ResolvedPage =
74+
val props = Map("page" -> JMap("title" -> title()))
75+
resolveInner(RenderingContext(props, ctx.layouts))
7476

7577
private[site] def resolveInner(ctx: RenderingContext): ResolvedPage =
7678
if (ctx.resolving.contains(file.getAbsolutePath))
@@ -82,9 +84,10 @@ case class TemplateFile(
8284
// Library requires mutable maps..
8385
val mutableProperties = new java.util.HashMap[String, Object](ctx.properties.asJava)
8486
val rendered = Template.parse(this.rawCode).render(mutableProperties)
85-
val code = if (!isHtml) rendered else
87+
// We want to render markdown only if next template is html
88+
val code = if (isHtml || layoutTemplate.exists(!_.isHtml)) rendered else
8689
val parser: Parser = Parser.builder().build()
87-
HtmlRenderer.builder(ctx.markdownOptions).build().render(parser.parse(rendered))
90+
HtmlRenderer.builder(defaultMarkdownOptions).build().render(parser.parse(rendered))
8891

8992
val resources = listSetting("extraCSS") ++ listSetting("extraJS")
9093
layoutTemplate match

scala3doc/src/dotty/renderers/DotDiagramBuilder.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package dotty.dokka
33
import dotty.dokka.model._
44
import org.jetbrains.dokka.model._
55
import org.jetbrains.dokka.links.DRI
6-
import org.jetbrains.dokka.base.resolvers.local.LocationProvider
76
import org.jetbrains.dokka.pages._
87
import dotty.dokka.model.api.Kind
98
import HTML._

scala3doc/src/dotty/renderers/ScalaHtmlRenderer.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import org.jetbrains.dokka._
88
import HTML._
99
import collection.JavaConverters._
1010
import java.net.URI
11+
import java.net.URL
1112
import java.util.{List => JList, Set => JSet}
1213
import kotlinx.html.FlowContent
1314
import kotlinx.html.stream.StreamKt
@@ -21,6 +22,7 @@ import dotty.dokka.model.api.HierarchyGraph
2122
import org.jetbrains.dokka.base.resolvers.local.LocationProvider
2223
import dotty.dokka.site.StaticPageNode
2324
import dotty.dokka.site.PartiallyRenderedContent
25+
import scala.util.Try
2426

2527
class SignatureRenderer(pageContext: ContentPage, sourceSetRestriciton: JSet[DisplaySourceSet], locationProvider: LocationProvider):
2628
def link(dri: DRI): Option[String] = Option(locationProvider.resolve(dri, sourceSetRestriciton, pageContext))
@@ -240,7 +242,13 @@ class ScalaHtmlRenderer(ctx: DokkaContext) extends HtmlRenderer(ctx) {
240242

241243
page.getContent match
242244
case prc: PartiallyRenderedContent =>
243-
withHtml(context, prc.resolved.code)
245+
def processLocalLink(str: String): String =
246+
// TODO (https://github.com/lampepfl/scala3doc/issues/238) error handling
247+
prc.context.driForLink(prc.template, str).toOption
248+
.flatMap(dri => Option(getLocationProvider.resolve(dri, sourceSets, page)))
249+
.getOrElse(str)
250+
251+
withHtml(context, prc.procsesHtml(url => Try(URL(url)).fold(_ => processLocalLink(url), _ => url)))
244252
case content =>
245253
build(content, context, page, /*sourceSetRestriction=*/null)
246254

0 commit comments

Comments
 (0)