Skip to content

Commit dd6d83e

Browse files
committed
Add snippet compiler docs
1 parent 86172db commit dd6d83e

12 files changed

+236
-8
lines changed

_overviews/scala3-scaladoc/search-engine.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: Type-based search
44
partof: scala3-scaladoc
55
num: 7
66
previous-page: site-versioning
7-
next-page: settings
7+
next-page: snippet-compiler
88
---
99

1010
Searching for functions by their symbolic names can be time-consuming.

_overviews/scala3-scaladoc/settings.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
layout: multipage-overview
33
title: Settings
44
partof: scala3-scaladoc
5-
num: 8
6-
previous-page: search-engine
5+
num: 9
6+
previous-page: snippet-compiler
77
---
88

99
This chapter lists the configuration options that can be used when calling scaladoc. Some of the information shown here can be found by calling scaladoc with the `-help` flag.
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
---
2+
layout: multipage-overview
3+
title: Snippet checking
4+
partof: scala3-scaladoc
5+
num: 8
6+
previous-page: search-engine
7+
next-page: settings
8+
---
9+
10+
The main functionality of documentation is to help people understand and use the project properly. Sometimes a part of a project needs few words to show its usage, but every developer knows that there are moments where description is not enough and nothing is better than a good ol’ example. A convenient way of providing examples in documentation is to create code snippets presenting usage of given functionality. The problem with code snippets is that simultaneously with project development, they need to be updated. Sometimes changes in one part of a project may break examples in other parts. The number of snippets and the amount of time passed since they’ve been written makes it impossible to remember every place where you need to fix them. After some time you realize that your documentation is a complete mess and you need to go through all examples and rewrite them. Many Scala 2 projects use typechecked markdown documentation with [tut](https://tpolecat.github.io/tut/) or [mdoc](https://scalameta.org/mdoc/). Almost everyone at least heard about these tools. As they turned out to be very useful and the Scala community successfully adopted them, we’re planning to incorporate the features of tut and mdoc into the compiler so that it’s included out of the box with Scaladoc.
11+
12+
![]({{ site.baseurl }}/resources/images/scala3/scaladoc/snippet-compiler3.png)
13+
14+
## Getting started
15+
16+
By default, snippet validation is turned off for all snippets. It can be turned on by adding the following argument to Scaladoc:
17+
18+
`-snippet-compiler:compile`
19+
20+
For sbt, it might look like this:
21+
22+
```scala
23+
Compile / doc / scalacOptions ++= Seq("-snippet-compiler:compile")
24+
```
25+
26+
This option turns on the snippet compiler for all `scala` snippets of the project documentation (it recognizes them by ```scala part). Currently, snippet validation works in both docstrings written in Markdown and static sites.
27+
![]({{ site.baseurl }}/resources/images/scala3/scaladoc/snippet-compiler4.png)
28+
29+
If you are starting new project, this configuration should be enough for you. However, in case you migrate existing project you might want to disable compilation for some snippets that can't be currently fixed.
30+
31+
To do this, you can add a flag directly to the snippet:
32+
33+
````
34+
```scala sc:nocompile
35+
// under the hood `map` is transformed into
36+
List(1).map( _ + 1)(<implicits>)
37+
```
38+
````
39+
40+
Sometimes compilation failure is an intended behavior. For that case, we exposed a flag `fail` that introduces one of our features: [Assert compilation errors](#assert-compilation-errors).
41+
42+
````
43+
```scala sc:fail
44+
List(1,2,3).toMap
45+
```
46+
````
47+
48+
For more thorough explanation and more sophisticated configuration e.g. path-based flag settings see [Advanced configuration](#advanced-configuration) section.
49+
50+
## Features overview
51+
52+
### Assert compilation errors
53+
54+
Scala is a statically typed programming language. Sometimes, documentation should mention cases where code should not compile,or authors want to provide ways to recover from certain compilation errors.
55+
56+
Example:
57+
58+
```scala
59+
List(1,2,3).toMap
60+
```
61+
62+
results in:
63+
64+
```nohighlight
65+
66+
At 18:21:
67+
List(1,2,3).toMap
68+
Error: Cannot prove that Int <:< (K, V)
69+
70+
where: K is a type variable with constraint
71+
V is a type variable with constraint
72+
.
73+
```
74+
75+
Examples presenting code that fails at compile-time are sometimes very important. For example you can show how the library is secured against incorrect code. The other use case is to present common mistakes and how to solve them. Taking that into account, we decided to provide a functionality to check if the marked code snippets don’t compile.
76+
77+
For snippet that fails to compile:
78+
````
79+
```scala sc:fail
80+
List(1,2,3).toMap
81+
```
82+
````
83+
passes the snippet validation and shows expected compilation errors in documentation.
84+
![]({{ site.baseurl }}/resources/images/scala3/scaladoc/assert-compilation-errors.gif)
85+
86+
For snippet that compiles without error:
87+
````
88+
```scala sc:fail
89+
List((1,2), (2,3)).toMap
90+
```
91+
````
92+
results in:
93+
```nohighlight
94+
95+
In static site (./docs/docs/index.md):
96+
Error: Snippet should not compile but compiled succesfully
97+
```
98+
99+
100+
### Context
101+
102+
Our goal is to make snippets behave as much as possible as if they were defined within a given scope (in a certain package, inside a class). We believe it brings a natural feel to snippets. To achieve this, we implemented a wrapping mechanism that provides a context for each snippet. The preprocessing is done automatically for all snippets in docstrings.
103+
104+
Let's assume that we want to document the method `slice` in a `collection.List`.
105+
106+
We want to explain how it works by comparing it to a combination of `drop` and `take` method so using snippet like:
107+
```scala
108+
slice(2, 5) == drop(2).take(3)
109+
```
110+
is one of the first thing that comes to mind. As you probably have guessed, this will not compile without a **context** feature.
111+
112+
Besides our main goal, it reduces the boilerplate of a snippet, because you don’t need to import members of the same package and instantiate documented class.
113+
114+
For people that are curious how our context mechanism works, the snippet after preprocessing will look like this:
115+
116+
```scala
117+
package scala.collection
118+
trait Snippet[A] { self: List[A] =>
119+
slice(2,5) == drop(2).take(3)
120+
}
121+
```
122+
123+
### Hiding code
124+
125+
Despite having the context feature described above, sometimes an author needs to provide more elements to scope. A big block of imports and initializations of necessary classes can result in loss of readablity. On the other hand, we’ve read a lot of opinions that people would like to be able to see the whole code. For that case we introduced special syntax for snippets that hides certain fragments of code, but you can always expand the snippet in documentation.
126+
127+
Example:
128+
129+
```scala
130+
//{
131+
import scala.collection.immutable.List
132+
//}
133+
val intList: List[Int] = List(1, 2, 3)
134+
```
135+
136+
![]({{ site.baseurl }}/resources/images/scala3/scaladoc/hiding-code.gif)
137+
138+
### Snippet includes
139+
140+
While writing code snippets, we often need a mechanism to reuse code from one snippet in another.
141+
142+
Take a look at the following piece of documentation:
143+
144+
![]({{ site.baseurl }}/resources/images/scala3/scaladoc/documentation-snippet.png)
145+
146+
To successfully compile the last snippet, we need to have previously declared definitions in scope. For this scenario and probably many more we added a new feature: snippet includes. It allows you to reuse code from one snippet in another which results in less redundancy and better maintainability.
147+
148+
To configure it, you need to add a `sc-name` argument directly in the snippet that you want to include:
149+
150+
```` ```scala sc-name:<snippet-name> ````
151+
152+
where `snippet-name` should be unique in file scope and cannot contain whitespaces and commas.
153+
154+
Then, you can add a `sc-compile-with` argument directly in the snippet that should contain include:
155+
```` ```scala sc-compile-with:<snippet-name>(,<snippet-name>)+ ````
156+
157+
where `snippet-name` is the name of snippet that should be included.
158+
159+
After configuring this feature in our example, the code looks like this:
160+
161+
![]({{ site.baseurl }}/resources/images/scala3/scaladoc/documentation-snippet2.png)
162+
163+
And the output looks like this:
164+
165+
![]({{ site.baseurl }}/resources/images/scala3/scaladoc/snippet-includes.png)
166+
167+
You can specify more than one include. The order in which they are specified defines the order of inclusion.
168+
169+
**Warning**: you can only include snippets that are defined above the target snippet.
170+
171+
## Advanced configuration
172+
173+
Often turning on snippet valiation for all snippets is not enough as the usecases can be more sophisticated. We prepared our tool for such situations to allow user adjust it to his needs.
174+
175+
### Available flags
176+
177+
Snippet compiler exposes three flags that change its behavior:
178+
- `compile` - turns on snippet checking
179+
- `nocompile` - turns off snippet checking
180+
- `fail` - turns on snippet checking with assertion that snippets don't compile
181+
182+
### Path-based settings
183+
184+
Instead of setting one flag to all snippets in project, it can be set for certain path only. It can be done by adding `<path>=` prefix before flag.
185+
186+
Example:
187+
188+
`-snippet-compiler:docs=compile` - sets `compile` flag for snippets in `docs` file. If `docs` is a directory, the flag is set for all files inside `docs`.
189+
190+
Additionally, `-snippet-compiler` option can be supplied by more than one setting. Settings are delimited by commas.
191+
192+
Example:
193+
```
194+
-snippet-compiler:docs=compile,library/src=compile,library/src/scala/quoted=nocompile,library/src/scala/compiletime=fail
195+
```
196+
Flags are chosen by longest prefix match so we can define a general setting and then change behavior for more specific paths.
197+
```
198+
-snippet-compiler:compile,library/src/scala/quoted=nocompile,library/src/scala/compiletime=fail
199+
```
200+
Flag without path prefix is treated as default.
201+
202+
### Override directly in the snippet
203+
204+
CLI arguments are a good mechanism for setting flags for certain files. However, it cannot be used to configure snippet compiler for certain snippet. For example an author wants to write one snippet that should fail and few snippets that compile. We took that under consideration and added a feature to override settings directly in the snippet. These arguments are located in snippet info part:
205+
206+
207+
````
208+
```scala <snippet-compiler-args>
209+
// snippet
210+
```
211+
````
212+
213+
In order to configure snippet checking for specific snippet, add following argument to its snippet info part:
214+
215+
`sc:<flag>`
216+
217+
where flag is one of available flags (see above).
218+
219+
````
220+
```scala sc:fail
221+
val itShouldFail: Int = List(1.1, 2, 3).head
222+
```
223+
````
224+
225+
226+
Loading
Loading
Loading
Loading
Loading
Loading
Loading

scala3/guides.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ guides:
1919
url: "/scala3/guides/tasty-overview.html"
2020
description: "An overview over the TASTy format aimed at end-users of the Scala language."
2121
- title: Scaladoc
22-
by: Krzysztof Romanowski, Aleksander Boruch-Gruszecki, Andrzej Ratajczak, Kacper Korban
22+
by: Krzysztof Romanowski, Aleksander Boruch-Gruszecki, Andrzej Ratajczak, Kacper Korban, Filip Zybała
2323
icon: book
2424
url: "/scala3/guides/scaladoc"
2525
description: "Scala’s API documentation generation tool."

scala3/scaladoc.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,18 @@ Furthermore, Scaladoc provides an easy way to configure your [social media links
4343

4444
The following features are currently (May 2021) not stable to be released with scaladoc, however we are happy to hear your feedback. Each feature has its own thread at scala-lang contributors site, where you can share your opinions.
4545

46-
### Snippets compiler
46+
### Snippet compiling
4747

4848
One of the experimental features of Scaladoc will be a snippets compiler. This tool will allow you to compile snippets that you attach to your docstring
4949
to check that they actually behave as intended, e. g. compile or throw some exception. The feature is very similar to `tut` or `mdoc` tools,
5050
but will be shipped with Scaladoc out of the box for easy setup and integration into your project. Making snippets interactive, e. g. user could edit them and compile in the browser is under consideration, though it is not in scope yet.
5151

52-
For more information you can follow this [thread](https://contributors.scala-lang.org/t/snippet-validation-in-scaladoc-for-scala-3/4976)
52+
Showcase:
53+
* Hiding code ![]({{ site.baseurl }}/resources/images/scala3/scaladoc/hiding-code.gif)
54+
* Assert compilation errors ![]({{ site.baseurl }}/resources/images/scala3/scaladoc/assert-compilation-errors.gif)
55+
* Snippet includes ![]({{ site.baseurl }}/resources/images/scala3/scaladoc/snippet-includes.png)
5356

54-
![](../resources/images/scala3/scaladoc/snippet-compiler2.gif)
55-
![](../resources/images/scala3/scaladoc/snippet-compiler1.gif)
57+
For more information see [Guides](/scala3/guides/scaladoc/snippet-compiler.html) or follow this [thread](https://contributors.scala-lang.org/t/snippet-validation-in-scaladoc-for-scala-3/4976)
5658

5759
### Type-based search
5860

0 commit comments

Comments
 (0)