Skip to content

Commit 8ddb298

Browse files
committed
Run snippet compiler on static sites
1 parent bcea268 commit 8ddb298

16 files changed

+169
-89
lines changed

scaladoc-testcases/docs/docs/index.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
3+
4+
---
5+
6+
```scala sc:compile
7+
2 + List(0)
8+
```
9+

scaladoc-testcases/src/tests/snippetCompilerTest.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ package snippetCompiler
2727
* val d: Long = "asd"
2828
* ```
2929
*
30-
* ```scala sc:failing
30+
* ```scala sc:fail
3131
* def a = 2
3232
* val x = 1 + List()
3333
* a
3434
* ```
3535
*
36-
* ```scala sc:failing
36+
* ```scala sc:fail
3737
* def a = 2
3838
* ```
3939
*
@@ -45,7 +45,6 @@ package snippetCompiler
4545
class A { }
4646

4747
/**
48-
*
4948
* ```scala sc:compile
5049
* val c: Int = 4.5
5150
* ```

scaladoc/src/dotty/tools/scaladoc/DocContext.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,15 @@ case class DocContext(args: Scaladoc.Args, compilerContext: CompilerContext):
7676

7777
lazy val snippetCompilerArgs = snippets.SnippetCompilerArgs.load(args.snippetCompiler, args.snippetCompilerDebug)(using compilerContext)
7878

79+
lazy val snippetChecker = snippets.SnippetChecker(args.classpath, args.tastyDirs)
80+
7981
lazy val staticSiteContext = args.docsRoot.map(path => StaticSiteContext(
8082
File(path).getAbsoluteFile(),
8183
args,
82-
sourceLinks
84+
sourceLinks,
85+
snippetCompilerArgs,
86+
snippetChecker
8387
)(using compilerContext))
8488

89+
8590
val externalDocumentationLinks = args.externalMappings

scaladoc/src/dotty/tools/scaladoc/site/LoadedTemplate.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,4 @@ case class LoadedTemplate(
5151
("site" -> (getMap("site") + ("posts" -> posts))) + ("urls" -> sourceLinks.toMap) +
5252
("page" -> (getMap("page") + ("title" -> templateFile.title)))
5353

54-
templateFile.resolveInner(RenderingContext(updatedSettings, ctx.layouts))
54+
templateFile.resolveInner(RenderingContext(updatedSettings, ctx.layouts))(using ctx)

scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import collection.JavaConverters._
1313
class StaticSiteContext(
1414
val root: File,
1515
val args: Scaladoc.Args,
16-
val sourceLinks: SourceLinks)(using val outerCtx: CompilerContext):
16+
val sourceLinks: SourceLinks,
17+
val snippetCompilerArgs: snippets.SnippetCompilerArgs,
18+
val snippetChecker: snippets.SnippetChecker)(using val outerCtx: CompilerContext):
1719

1820
var memberLinkResolver: String => Option[DRI] = _ => None
1921

scaladoc/src/dotty/tools/scaladoc/site/common.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ val defaultMarkdownOptions: DataHolder =
3636
EmojiExtension.create(),
3737
YamlFrontMatterExtension.create(),
3838
StrikethroughExtension.create(),
39-
WikiLinkExtension.create()
39+
WikiLinkExtension.create(),
40+
tasty.comments.markdown.SnippetRenderingExtension
4041
))
4142

4243
def emptyTemplate(file: File, title: String): TemplateFile = TemplateFile(

scaladoc/src/dotty/tools/scaladoc/site/templates.scala

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package dotty.tools.scaladoc
22
package site
33

44
import java.io.File
5-
import java.nio.file.Files
5+
import java.nio.file.{Files, Paths}
66

77
import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension
88
import com.vladsch.flexmark.ext.autolink.AutolinkExtension
@@ -18,6 +18,7 @@ import liqp.Template
1818
import scala.collection.JavaConverters._
1919

2020
import scala.io.Source
21+
import dotty.tools.scaladoc.snippets._
2122

2223
case class RenderingContext(
2324
properties: Map[String, Object],
@@ -55,7 +56,22 @@ case class TemplateFile(
5556
):
5657
def isIndexPage() = file.isFile && (file.getName == "index.md" || file.getName == "index.html")
5758

58-
private[site] def resolveInner(ctx: RenderingContext): ResolvedPage =
59+
private[site] def resolveInner(ctx: RenderingContext)(using ssctx: StaticSiteContext): ResolvedPage =
60+
61+
lazy val snippetCheckingFunc: SnippetChecker.SnippetCheckingFunc =
62+
val path = Some(Paths.get(file.getAbsolutePath))
63+
val pathBasedArg = ssctx.snippetCompilerArgs.get(path)
64+
(str: String, lineOffset: SnippetChecker.LineOffset, argOverride: Option[SCFlags]) => {
65+
val arg = argOverride.fold(pathBasedArg)(pathBasedArg.overrideFlag(_))
66+
ssctx.snippetChecker.checkSnippet(str, None, arg, lineOffset).collect {
67+
case r: SnippetCompilationResult if !r.isSuccessful =>
68+
val msg = s"In static site (${file.getAbsolutePath}):\n${r.getSummary}"
69+
report.error(msg)(using ssctx.outerCtx)
70+
r
71+
case r => r
72+
}
73+
}
74+
5975
if (ctx.resolving.contains(file.getAbsolutePath))
6076
throw new RuntimeException(s"Cycle in templates involving $file: ${ctx.resolving}")
6177

@@ -74,9 +90,13 @@ case class TemplateFile(
7490
val rendered = Template.parse(this.rawCode).render(mutableProperties)
7591
// We want to render markdown only if next template is html
7692
val code = if (isHtml || layoutTemplate.exists(!_.isHtml)) rendered else
93+
// Snippet compiler currently supports markdown only
7794
val parser: Parser = Parser.builder(defaultMarkdownOptions).build()
78-
HtmlRenderer.builder(defaultMarkdownOptions).build().render(parser.parse(rendered))
95+
val parsedMd = parser.parse(rendered)
96+
val processed = FlexmarkSnippetProcessor.processSnippets(parsedMd, ssctx.snippetCompilerArgs.debug, snippetCheckingFunc)
97+
HtmlRenderer.builder(defaultMarkdownOptions).build().render(processed)
98+
7999
layoutTemplate match
80100
case None => ResolvedPage(code, resources ++ ctx.resources)
81101
case Some(layoutTemplate) =>
82-
layoutTemplate.resolveInner(ctx.nest(code, file, resources))
102+
layoutTemplate.resolveInner(ctx.nest(code, file, resources))
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package dotty.tools.scaladoc
2+
package snippets
3+
4+
import com.vladsch.flexmark.util.{ast => mdu, sequence}
5+
import com.vladsch.flexmark.{ast => mda}
6+
import com.vladsch.flexmark.formatter.Formatter
7+
import com.vladsch.flexmark.util.options.MutableDataSet
8+
import collection.JavaConverters._
9+
10+
import dotty.tools.scaladoc.tasty.comments.markdown.ExtendedFencedCodeBlock
11+
12+
object FlexmarkSnippetProcessor:
13+
def processSnippets(root: mdu.Node, debug: Boolean, checkingFunc: => SnippetChecker.SnippetCheckingFunc): mdu.Node = {
14+
lazy val cf: SnippetChecker.SnippetCheckingFunc = checkingFunc
15+
16+
val nodes = root.getDescendants().asScala.collect {
17+
case fcb: mda.FencedCodeBlock => fcb
18+
}.toList
19+
20+
nodes.foreach { node =>
21+
val snippet = node.getContentChars.toString
22+
val lineOffset = node.getStartLineNumber
23+
val info = node.getInfo.toString
24+
val argOverride =
25+
info.split(" ")
26+
.find(_.startsWith("sc:"))
27+
.map(_.stripPrefix("sc:"))
28+
.map(SCFlagsParser.parse)
29+
.flatMap(_.toOption)
30+
val snippetCompilationResult = cf(snippet, lineOffset, argOverride) match {
31+
case result@Some(SnippetCompilationResult(wrapped, _, _, _)) if debug =>
32+
val s = sequence.BasedSequence.EmptyBasedSequence()
33+
.append(wrapped)
34+
.append(sequence.BasedSequence.EOL)
35+
val content = mdu.BlockContent()
36+
content.add(s, 0)
37+
node.setContent(content)
38+
result
39+
case result => result
40+
}
41+
42+
node.insertBefore(new ExtendedFencedCodeBlock(node, snippetCompilationResult))
43+
node.unlink()
44+
}
45+
46+
root
47+
}

scaladoc/src/dotty/tools/scaladoc/snippets/SnippetChecker.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ package snippets
33

44
import dotty.tools.scaladoc.DocContext
55
import java.nio.file.Paths
6+
import java.io.File
67

7-
class SnippetChecker()(using ctx: DocContext):
8+
class SnippetChecker(val classpath: String, val tastyDirs: Seq[File]):
89
private val sep = System.getProperty("path.separator")
9-
private val cp = System.getProperty("java.class.path") + sep +
10-
Paths.get(ctx.args.classpath).toAbsolutePath + sep +
11-
ctx.args.tastyDirs.map(_.getAbsolutePath()).mkString(sep)
10+
private val cp = List(
11+
System.getProperty("java.class.path"),
12+
Paths.get(classpath).toAbsolutePath,
13+
tastyDirs.map(_.getAbsolutePath()).mkString(sep)
14+
).mkString(sep)
15+
1216
private val compiler: SnippetCompiler = SnippetCompiler(classpath = cp)
1317

1418
def checkSnippet(

scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,16 @@ class SnippetCompiler(
4242
private def nullableMessage(msgOrNull: String): String =
4343
if (msgOrNull == null) "" else msgOrNull
4444

45-
private def createReportMessage(diagnostics: Seq[Diagnostic], line: Int, column: Int): Seq[SnippetCompilerMessage] = {
45+
private def createReportMessage(wrappedSnippet: WrappedSnippet, arg: SnippetCompilerArg, diagnostics: Seq[Diagnostic]): Seq[SnippetCompilerMessage] = {
46+
val line = wrappedSnippet.lineOffset
47+
val column = wrappedSnippet.columnOffset
48+
val lineBoilerplate = wrappedSnippet.lineBoilerplate
4649
val infos = diagnostics.toSeq.sortBy(_.pos.source.path)
4750
val errorMessages = infos.map {
4851
case diagnostic if diagnostic.position.isPresent =>
4952
val diagPos = diagnostic.position.get
5053
val pos = Some(
51-
Position(diagPos.line + line, diagPos.column + column, diagPos.lineContent, diagPos.line)
54+
Position(diagPos.line + line, diagPos.column + column, diagPos.lineContent, if arg.debug then diagPos.line else diagPos.line - lineBoilerplate)
5255
)
5356
val msg = nullableMessage(diagnostic.message)
5457
val level = MessageLevel.fromOrdinal(diagnostic.level)
@@ -85,7 +88,7 @@ class SnippetCompiler(
8588
run.compileFromStrings(List(wrappedSnippet.snippet))
8689

8790
val messages =
88-
createReportMessage(context.reporter.pendingMessages(using context), wrappedSnippet.lineOffset, wrappedSnippet.columnOffset) ++
91+
createReportMessage(wrappedSnippet, arg, context.reporter.pendingMessages(using context)) ++
8992
additionalMessages(wrappedSnippet, arg, context)
9093

9194
val t = Option.when(!context.reporter.hasErrors)(target)

0 commit comments

Comments
 (0)