Skip to content

Commit 0f870aa

Browse files
authored
Merge pull request #6 from KacperFKorban/scaladoc/snippet-compilation-messages
Display snippet compilation messages in scaladoc
2 parents dc90d29 + 0cbbd2f commit 0f870aa

File tree

9 files changed

+268
-57
lines changed

9 files changed

+268
-57
lines changed

scaladoc-js/resources/scaladoc-searchbar.css

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -105,27 +105,33 @@
105105

106106
.snippet-comment-button {
107107
position: absolute;
108+
display: inline-block;
108109
left: 50%;
109110
width: 24px;
110111
height: 24px;
111-
}
112-
113-
.show-snippet-comments-button {
114-
-ms-transform: translate(calc(-50% + 5em), -50%);
115-
transform: translate(calc(-50% + 5em), -50%);
116-
background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Ccircle cx='12' cy='12' r='12' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M19 11.0053L19 13.1085H12.9873L12.988 19H10.8714L10.8721 13.1085L5 13.1085L5 11.0053L10.8721 11.0053V5L12.9865 5.00074L12.988 11.0045L19 11.0053Z' fill='%2327282C' fill-opacity='0.75'/%3E %3C/svg%3E");
117-
}
118-
119-
.show-snippet-comments-button:hover {
120-
background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Ccircle cx='12' cy='12' r='12' fill='light grey'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M19 11.0053L19 13.1085H12.9873L12.988 19H10.8714L10.8721 13.1085L5 13.1085L5 11.0053L10.8721 11.0053V5L12.9865 5.00074L12.988 11.0045L19 11.0053Z' fill='%2327282C' fill-opacity='0.75'/%3E %3C/svg%3E");
112+
background:
113+
linear-gradient(#fff, #fff),
114+
linear-gradient(#fff, #fff),
115+
#aaa;
116+
background-position: center;
117+
background-size: 50% 2px, 2px 50%;
118+
background-repeat: no-repeat;
119+
border-radius: 12px;
120+
box-shadow: 0 0 2px black;
121+
}
122+
123+
.snippet-comment-button:hover {
124+
background:
125+
linear-gradient(#444, #444),
126+
linear-gradient(#444, #444),
127+
#ddd;
128+
background-position: center;
129+
background-size: 50% 2px, 2px 50%;
130+
background-repeat: no-repeat;
121131
}
122132

123133
.hide-snippet-comments-button {
124-
-ms-transform: translate(calc(-50% + 5em), -50%) rotate(45deg);
125-
transform: translate(calc(-50% + 5em), -50%) rotate(45deg);
126-
background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Ccircle cx='12' cy='12' r='12' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M19 11.0053L19 13.1085H12.9873L12.988 19H10.8714L10.8721 13.1085L5 13.1085L5 11.0053L10.8721 11.0053V5L12.9865 5.00074L12.988 11.0045L19 11.0053Z' fill='%2327282C' fill-opacity='0.75'/%3E %3C/svg%3E");
134+
-ms-transform: rotate(45deg);
135+
transform: rotate(45deg);
127136
}
128137

129-
.hide-snippet-comments-button:hover {
130-
background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Ccircle cx='12' cy='12' r='12' fill='light grey'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M19 11.0053L19 13.1085H12.9873L12.988 19H10.8714L10.8721 13.1085L5 13.1085L5 11.0053L10.8721 11.0053V5L12.9865 5.00074L12.988 11.0045L19 11.0053Z' fill='%2327282C' fill-opacity='0.75'/%3E %3C/svg%3E");
131-
}

scaladoc-js/src/searchbar/code-snippets/CodeSnippets.scala

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,6 @@ import org.scalajs.dom._
44
import org.scalajs.dom.ext._
55

66
class CodeSnippets:
7-
val replacePatternsAndResults: Seq[(String, String)] = Seq(
8-
"""(\/\/{{\n)((.|\n)*?)(\/\/}}\n)""" -> """<span class="hideable">$2</span>""", // wrap content of block directives
9-
"""(\/\/.*?)(\n|\$)""" -> """<span class="hideable">$1</span>$2""", // wrap single line comment
10-
"""(\/\*)((.|\n)*?)(\*\/)""" -> """<span class="hideable">$0</span>""", // wrap multi line comment
11-
)
12-
13-
document.querySelectorAll("code").foreach {
14-
case e: html.Element => e.innerHTML = replacePatternsAndResults.foldLeft(e.innerHTML) {
15-
case (acc, (pattern, result)) =>
16-
acc.replaceAll(pattern, result)
17-
}
18-
}
19-
207
def toggleHide(e: html.Element | html.Document) = e.querySelectorAll("code span.hideable").foreach {
218
case e: html.Element if e.style.getPropertyValue("display").isEmpty => e.style.setProperty("display", "none")
229
case e: html.Element => e.style.removeProperty("display")
@@ -29,15 +16,12 @@ class CodeSnippets:
2916
val a = document.createElement("a")
3017
a.addEventListener("click", { (_: MouseEvent) =>
3118
if(a.classList.contains("hide-snippet-comments-button")) {
32-
a.classList.add("show-snippet-comments-button")
3319
a.classList.remove("hide-snippet-comments-button")
3420
} else {
3521
a.classList.add("hide-snippet-comments-button")
36-
a.classList.remove("show-snippet-comments-button")
3722
}
3823
toggleHide(e)
3924
})
4025
a.classList.add("snippet-comment-button")
41-
a.classList.add("show-snippet-comments-button")
4226
e.insertBefore(a, e.firstChild)
4327
}

scaladoc-testcases/src/tests/snippetCompilerTest.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,29 @@ package snippetCompiler
22

33
/**
44
* ```scala sc:compile
5+
* //{
6+
* import scala.collection.Seq
7+
* //}
8+
*
59
* def a = 2
610
* val x = 1 + List()
711
* a
12+
*
13+
* try {
14+
* 2+3
15+
* }
16+
*
17+
* /*
18+
* Huge comment
19+
* */
20+
* val xd: String = 42
21+
*
22+
* def a(i: Int): Boolean = i match // This is a function
23+
* case 1 => true
24+
*
25+
* val b: Int = 2.3 /* Also quite a big comment */
26+
*
27+
* val d: Long = "asd"
828
* ```
929
*
1030
* ```scala sc:failing
@@ -23,3 +43,11 @@ package snippetCompiler
2343
* ```
2444
*/
2545
class A { }
46+
47+
/**
48+
*
49+
* ```scala sc:compile
50+
* val c: Int = 4.5
51+
* ```
52+
*/
53+
class B { }

scaladoc/resources/dotty_res/styles/scalastyle.css

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,18 +93,53 @@ code {
9393
padding: 0 .3em;
9494
}
9595
pre {
96-
overflow-x: auto;
9796
scrollbar-width: thin;
97+
margin: 0px;
9898
}
9999
pre code, pre code.hljs {
100100
font-size: 1em;
101101
padding: 0;
102102
}
103-
pre, .symbol.monospace {
103+
.snippet {
104104
padding: 12px 8px 10px 12px;
105+
background: var(--code-bg);
106+
margin: 1em 0px;
107+
border-radius: 2px;
108+
box-shadow: 0 0 2px #888;
109+
}
110+
.snippet-error {
111+
border-bottom: 2px dotted red;
112+
}
113+
.snippet-warn {
114+
border-bottom: 2px dotted orange;
115+
}
116+
.snippet-info {
117+
border-bottom: 2px dotted teal;
118+
}
119+
.snippet-debug {
120+
border-bottom: 2px dotted pink;
121+
}
122+
.tooltip {
123+
position: relative;
124+
}
125+
.tooltip:hover:after {
126+
content: attr(label);
127+
padding: 4px 8px;
128+
color: white;
129+
background-color:black;
130+
position: absolute;
131+
left: 0;
132+
z-index:10;
133+
box-shadow:0 0 3px #444;
134+
opacity: 0.8;
135+
}
136+
pre, .symbol.monospace {
105137
font-weight: 500;
106138
font-size: 12px;
107139
}
140+
.symbol.monospace {
141+
padding: 12px 8px 10px 12px;
142+
}
108143
a, a:visited, span[data-unresolved-link] {
109144
text-decoration: none;
110145
color: var(--link-fg);

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

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,21 @@ package snippets
33

44
import dotty.tools.io.{ AbstractFile }
55

6-
case class Position(line: Int, column: Int, sourceLine: String)
6+
case class Position(line: Int, column: Int, sourceLine: String, relativeLine: Int)
77

8-
case class SnippetCompilerMessage(position: Option[Position], message: String, level: MessageLevel)
8+
case class SnippetCompilerMessage(position: Option[Position], message: String, level: MessageLevel):
9+
def getSummary: String =
10+
position.fold(s"${level.text}: ${message}") { pos =>
11+
s"At ${pos.line}:${pos.column}:\n${pos.sourceLine}${level.text}: ${message}"
12+
}
913

1014
case class SnippetCompilationResult(
1115
wrappedSnippet: String,
1216
isSuccessful: Boolean,
1317
result: Option[AbstractFile],
1418
messages: Seq[SnippetCompilerMessage]
1519
):
16-
def getSummary: String =
17-
messages.map(m =>
18-
m.position.fold(
19-
s"${m.level.text}: ${m.message}"
20-
)(pos =>
21-
s"At ${pos.line}:${pos.column}:\n${pos.sourceLine}${m.level.text}: ${m.message}"
22-
)
23-
).mkString("\n")
24-
20+
def getSummary: String = messages.map(_.getSummary).mkString("\n")
2521

2622
enum MessageLevel(val text: String):
2723
case Info extends MessageLevel("Info")

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class SnippetCompiler(
4848
case diagnostic if diagnostic.position.isPresent =>
4949
val diagPos = diagnostic.position.get
5050
val pos = Some(
51-
Position(diagPos.line + line, diagPos.column + column, diagPos.lineContent)
51+
Position(diagPos.line + line, diagPos.column + column, diagPos.lineContent, diagPos.line)
5252
)
5353
val msg = nullableMessage(diagnostic.message)
5454
val level = MessageLevel.fromOrdinal(diagnostic.level)

scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.vladsch.flexmark.formatter.Formatter
1010
import com.vladsch.flexmark.util.options.MutableDataSet
1111

1212
import scala.quoted._
13+
import dotty.tools.scaladoc.tasty.comments.markdown.ExtendedFencedCodeBlock
1314
import dotty.tools.scaladoc.tasty.comments.wiki.Paragraph
1415
import dotty.tools.scaladoc.DocPart
1516
import dotty.tools.scaladoc.tasty.SymOps
@@ -182,15 +183,13 @@ abstract class MarkupConversion[T](val repr: Repr, snippetChecker: SnippetChecke
182183
(str: String, lineOffset: SnippetChecker.LineOffset, argOverride: Option[SCFlags]) => {
183184
val arg = argOverride.fold(pathBasedArg)(pathBasedArg.overrideFlag(_))
184185

185-
val res = snippetChecker.checkSnippet(str, Some(data), arg, lineOffset)
186-
snippetChecker.checkSnippet(str, Some(data), arg, lineOffset).foreach { _ match {
186+
snippetChecker.checkSnippet(str, Some(data), arg, lineOffset).collect {
187187
case r: SnippetCompilationResult if !r.isSuccessful =>
188188
val msg = s"In member ${s.name} (${s.dri.location}):\n${r.getSummary}"
189189
report.error(msg)(using dctx.compilerContext)
190-
case _ =>
191-
}
190+
r
191+
case r => r
192192
}
193-
res
194193
}
195194
}
196195

@@ -252,7 +251,7 @@ class MarkdownCommentParser(repr: Repr, snippetChecker: SnippetChecker)(using dc
252251
val nodes = root.getDescendants().asScala.collect {
253252
case fcb: mda.FencedCodeBlock => fcb
254253
}.toList
255-
if !nodes.isEmpty then {
254+
if nodes.nonEmpty then {
256255
val checkingFunc: SnippetChecker.SnippetCheckingFunc = snippetCheckingFunc(owner)
257256
nodes.foreach { node =>
258257
val snippet = node.getContentChars.toString
@@ -264,16 +263,32 @@ class MarkdownCommentParser(repr: Repr, snippetChecker: SnippetChecker)(using dc
264263
.map(_.stripPrefix("sc:"))
265264
.map(snippets.SCFlagsParser.parse)
266265
.flatMap(_.toOption)
267-
checkingFunc(snippet, lineOffset, argOverride) match {
268-
case Some(SnippetCompilationResult(wrapped, _, _, _)) if dctx.snippetCompilerArgs.debug =>
266+
val snippetCompilationResult = checkingFunc(snippet, lineOffset, argOverride) match {
267+
case result@Some(SnippetCompilationResult(wrapped, _, _, _)) if dctx.snippetCompilerArgs.debug =>
269268
val s = sequence.BasedSequence.EmptyBasedSequence()
270269
.append(wrapped)
271270
.append(sequence.BasedSequence.EOL)
272271
val content = mdu.BlockContent()
273272
content.add(s, 0)
274273
node.setContent(content)
275-
case _ =>
274+
result
275+
case result =>
276+
result.map { r =>
277+
r.copy(
278+
messages = r.messages.map { m =>
279+
m.copy(
280+
position = m.position.map { p =>
281+
p.copy(
282+
relativeLine = p.relativeLine - lineOffset
283+
)
284+
}
285+
)
286+
}
287+
)
288+
}
276289
}
290+
node.insertBefore(new ExtendedFencedCodeBlock(node, snippetCompilationResult))
291+
node.unlink()
277292
}
278293
}
279294
root

scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/DocFlexmarkExtension.scala

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,21 @@ import com.vladsch.flexmark.ext.wikilink.internal.WikiLinkLinkRefProcessor
1010
import com.vladsch.flexmark.util.ast._
1111
import com.vladsch.flexmark.util.options._
1212
import com.vladsch.flexmark.util.sequence.BasedSequence
13+
import com.vladsch.flexmark._
1314

15+
import dotty.tools.scaladoc.snippets._
16+
import scala.collection.JavaConverters._
1417

1518
class DocLinkNode(
1619
val target: DocLink,
1720
val body: String,
1821
seq: BasedSequence
19-
) extends WikiNode(seq, false, false, false, false)
22+
) extends WikiNode(seq, false, false, false, false)
23+
24+
case class ExtendedFencedCodeBlock(
25+
codeBlock: ast.FencedCodeBlock,
26+
compilationResult: Option[SnippetCompilationResult]
27+
) extends WikiNode(codeBlock.getChars, false, false, false, false)
2028

2129
class DocFlexmarkParser(resolveLink: String => DocLink) extends Parser.ParserExtension:
2230

@@ -49,13 +57,25 @@ case class DocFlexmarkRenderer(renderLink: (DocLink, String) => String)
4957
extends HtmlRenderer.HtmlRendererExtension:
5058
def rendererOptions(opt: MutableDataHolder): Unit = () // noop
5159

60+
object ExtendedFencedCodeBlockHandler extends CustomNodeRenderer[ExtendedFencedCodeBlock]:
61+
override def render(node: ExtendedFencedCodeBlock, c: NodeRendererContext, html: HtmlWriter): Unit =
62+
html.raw(
63+
SnippetRenderer.renderSnippetWithMessages(
64+
node.codeBlock.getContentChars.toString.split("\n").map(_ + "\n").toSeq,
65+
node.compilationResult.toSeq.flatMap(_.messages)
66+
)
67+
)
68+
5269
object Handler extends CustomNodeRenderer[DocLinkNode]:
5370
override def render(node: DocLinkNode, c: NodeRendererContext, html: HtmlWriter): Unit =
5471
html.raw(renderLink(node.target, node.body))
5572

5673
object Render extends NodeRenderer:
5774
override def getNodeRenderingHandlers: JSet[NodeRenderingHandler[_]] =
58-
JSet(new NodeRenderingHandler(classOf[DocLinkNode], Handler))
75+
JSet(
76+
new NodeRenderingHandler(classOf[DocLinkNode], Handler),
77+
new NodeRenderingHandler(classOf[ExtendedFencedCodeBlock], ExtendedFencedCodeBlockHandler),
78+
)
5979

6080
object Factory extends NodeRendererFactory:
6181
override def create(options: DataHolder): NodeRenderer = Render

0 commit comments

Comments
 (0)