Skip to content

Commit 64f66d0

Browse files
authored
Merge pull request #322 from ckipp01/single-file
2 parents 9913942 + 6ba97f7 commit 64f66d0

36 files changed

+847
-270
lines changed

build.sbt

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ inThisBuild(
99
scalaVersion := scala212,
1010
crossScalaVersions := List(scala212, scala211, scala213),
1111
scalacOptions ++= List(
12+
"-Yrangepos",
1213
"-Xexperimental",
1314
"-deprecation"
1415
),
@@ -36,7 +37,8 @@ inThisBuild(
3637
// faster publishLocal:
3738
publishArtifact.in(packageDoc) := "true" == System.getenv("CI"),
3839
publishArtifact.in(packageSrc) := "true" == System.getenv("CI"),
39-
turbo := true
40+
turbo := true,
41+
useSuperShell := false // overlaps with MUnit test failure reports.
4042
)
4143
)
4244

docs/installation.md

+50-5
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ The sbt-mdoc plugin supports the following settings.
119119

120120
```
121121

122-
123122
## Command-line
124123

125124
Use [coursier](https://github.com/coursier/coursier/#command-line) to launch
@@ -135,6 +134,8 @@ info: Compiling 1 file to website/target/docs
135134
info: Compiled in 1.2s (0 errors)
136135
```
137136

137+
### Add library dependencies to classpath
138+
138139
Add libraries to the launched classpath to include them for compilation.
139140

140141
```diff
@@ -143,14 +144,28 @@ Add libraries to the launched classpath to include them for compilation.
143144
+ org.typelevel:cats-core_@SCALA_BINARY_VERSION@:1.5.0
144145
```
145146

146-
Use `--in` to customize the input directory where markdown sources are
147-
contained, by default the `docs/` directory is used.
147+
### Customize input directory
148+
149+
By default the `docs/` directory is processed as input. Use `--in` to customize
150+
the input directory where markdown sources are contained,
148151

149152
```diff
150153
coursier launch org.scalameta:mdoc_@SCALA_BINARY_VERSION@:@VERSION@ -- \
151154
+ --in mydocs
152155
```
153156

157+
### Process single markdown file
158+
159+
The `--in` flag doesn't have to be a directory, it also supports individual
160+
files.
161+
162+
```diff
163+
coursier launch org.scalameta:mdoc_@SCALA_BINARY_VERSION@:@VERSION@ -- \
164+
+ --in mydocs/readme.md
165+
```
166+
167+
### Configure site variables like `@@VERSION@`
168+
154169
Use `--site.VARIABLE=value` to add site variables that can be referenced from
155170
markdown as `@@VARIABLE@`.
156171

@@ -159,14 +174,44 @@ markdown as `@@VARIABLE@`.
159174
+ --site.SCALA_VERSION @SCALA_VERSION@
160175
```
161176

162-
Use `--out` to customize the directory where markdown sources are generated, by
163-
default the `out/` directory is used.
177+
### Customize output directory
178+
179+
Use `--out` to customize where your markdown sources are generated, by default
180+
the `out/` directory is used.
164181

165182
```diff
166183
coursier launch org.scalameta:mdoc_@SCALA_BINARY_VERSION@:@VERSION@ -- \
167184
+ --out target/docs
168185
```
169186

187+
### Generate single output file instead of directory
188+
189+
The `--out` flag doesn't have to be a directory when the `--in` argument is a
190+
regular file, it can also be an individual file.
191+
192+
```diff
193+
coursier launch org.scalameta:mdoc_@SCALA_BINARY_VERSION@:@VERSION@ -- \
194+
+ --in readme.template.md \
195+
+ --out readme.md
196+
```
197+
198+
### Process multiple input directories and files
199+
200+
Repeat the `--in` and `--out` arguments to process multiple directories and
201+
regular files.
202+
203+
```diff
204+
coursier launch org.scalameta:mdoc_@SCALA_BINARY_VERSION@:@VERSION@ -- \
205+
+ --in readme.template.md \
206+
+ --out readme.md \
207+
+ --in changelog.template.md \
208+
+ --out changelog.md \
209+
+ --in mydocs-directory \
210+
+ --out out-directory \
211+
```
212+
213+
### Live reload HTML preview on file save
214+
170215
Use `--watch` to start the file watcher with livereload. It's recommended to use
171216
`--watch` while writing documentation to enjoy 3-4x faster compilation
172217
performance.

mdoc-docs/src/main/scala/mdoc/docs/MdocModifier.scala

+4-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import mdoc.internal.markdown.GitHubIdGenerator
1414
import mdoc.internal.markdown.LinkHygiene
1515
import mdoc.internal.pos.PositionSyntax._
1616
import mdoc.internal.markdown.MarkdownFile
17+
import mdoc.internal.cli.InputFile
1718

1819
class MdocModifier(context: Context) extends StringModifier {
1920
private val myStdout = new ByteArrayOutputStream()
@@ -24,16 +25,16 @@ class MdocModifier(context: Context) extends StringModifier {
2425
myStdout.reset()
2526
myReporter.reset()
2627
val cleanInput = Input.VirtualFile(code.filename, code.text)
27-
val relpath = RelativePath(code.filename)
28+
val file = InputFile.fromSettings(code.filename, context.settings)
2829
val markdown = Markdown.toMarkdown(
2930
cleanInput,
3031
myContext,
31-
relpath,
32+
file,
3233
myContext.settings.site,
3334
myReporter,
3435
myContext.settings
3536
)
36-
val links = DocumentLinks.fromMarkdown(GitHubIdGenerator, relpath, cleanInput)
37+
val links = DocumentLinks.fromMarkdown(GitHubIdGenerator, file.relpath, cleanInput)
3738
LinkHygiene.lint(List(links), myReporter, verbose = false)
3839
val stdout = fansi.Str(myStdout.toString()).plainText
3940
if (myReporter.hasErrors || myReporter.hasWarnings) {

mdoc-docs/src/main/scala/mdoc/docs/SbtModifier.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,5 @@ class SbtModifier extends StringModifier {
3939
</tr>
4040
{rows}
4141
</table>
42-
}.toString()
42+
}.toString() + "\n\n"
4343
}

mdoc-js/src/main/scala-2.12/mdoc/modifiers/JsConfig.scala

+4-9
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ case class JsConfig(
1515
libraries: List[AbsolutePath] = Nil,
1616
mountNode: String = "node",
1717
minLevel: Level = Level.Info,
18-
outDirectory: AbsolutePath = PathIO.workingDirectory,
18+
outDirectories: List[AbsolutePath] = List(PathIO.workingDirectory),
19+
outPrefix: Option[String] = None,
1920
fullOpt: Boolean = true,
2021
htmlPrefix: String = "",
2122
relativeLinkPrefix: String = ""
@@ -65,14 +66,8 @@ object JsConfig {
6566
ctx.site.getOrElse("js-html-header", ""),
6667
Classpath(ctx.site.getOrElse("js-libraries", "")).entries,
6768
mountNode = ctx.site.getOrElse("js-mount-node", base.mountNode),
68-
outDirectory = ctx.site.get("js-out-prefix") match {
69-
case Some(value) =>
70-
// This is needed for Docusaurus that requires assets (non markdown) files to live under
71-
// `docs/assets/`: https://docusaurus.io/docs/en/doc-markdown#linking-to-images-and-other-assets
72-
ctx.settings.out.resolve(value)
73-
case None =>
74-
ctx.settings.out
75-
},
69+
outDirectories = ctx.settings.out,
70+
outPrefix = ctx.site.get("js-out-prefix"),
7671
minLevel = ctx.site.get("js-level") match {
7772
case None => Level.Info
7873
case Some("info") => Level.Info

mdoc-js/src/main/scala-2.12/mdoc/modifiers/JsModifier.scala

+35-12
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import scala.meta.Term
2525
import scala.meta.inputs.Input
2626
import scala.meta.io.Classpath
2727
import scala.reflect.io.VirtualDirectory
28+
import mdoc.internal.cli.InputFile
29+
import scala.meta.io.AbsolutePath
2830

2931
class JsModifier extends mdoc.PreModifier {
3032
override val name = "js"
@@ -153,19 +155,40 @@ class JsModifier extends mdoc.PreModifier {
153155
} else {
154156
val output = WritableMemVirtualJSFile("output.js")
155157
linker.link(virtualIrFiles ++ sjsir, Nil, output, sjsLogger)
156-
val outjsfile = config.outDirectory.resolve(ctx.relativePath.resolveSibling(_ + ".js"))
157-
outjsfile.write(output.content)
158-
val outmdoc = outjsfile.resolveSibling(_ => "mdoc.js")
159-
outmdoc.write(Resources.readPath("/mdoc.js"))
160-
val relfile = outjsfile.toRelativeLinkFrom(ctx.outputFile, config.relativeLinkPrefix)
161-
val relmdoc = outmdoc.toRelativeLinkFrom(ctx.outputFile, config.relativeLinkPrefix)
162-
new CodeBuilder()
163-
.println(config.htmlHeader)
164-
.lines(config.libraryScripts(outjsfile, ctx))
165-
.println(s"""<script type="text/javascript" src="$relfile" defer></script>""")
166-
.println(s"""<script type="text/javascript" src="$relmdoc" defer></script>""")
167-
.toString
158+
ctx.settings.toInputFile(ctx.inputFile) match {
159+
case None =>
160+
ctx.reporter.error(
161+
s"unable to find output file matching the input file '${ctx.inputFile}'. " +
162+
s"To fix this problem, make sure that --in points to a directory that contains the file ${ctx.inputFile}."
163+
)
164+
""
165+
case Some(inputFile) =>
166+
val outjsfile = resolveOutputJsFile(inputFile)
167+
outjsfile.write(output.content)
168+
val outmdoc = outjsfile.resolveSibling(_ => "mdoc.js")
169+
outmdoc.write(Resources.readPath("/mdoc.js"))
170+
val relfile = outjsfile.toRelativeLinkFrom(ctx.outputFile, config.relativeLinkPrefix)
171+
val relmdoc = outmdoc.toRelativeLinkFrom(ctx.outputFile, config.relativeLinkPrefix)
172+
new CodeBuilder()
173+
.println(config.htmlHeader)
174+
.lines(config.libraryScripts(outjsfile, ctx))
175+
.println(s"""<script type="text/javascript" src="$relfile" defer></script>""")
176+
.println(s"""<script type="text/javascript" src="$relmdoc" defer></script>""")
177+
.toString
178+
}
179+
}
180+
}
181+
182+
private def resolveOutputJsFile(file: InputFile): AbsolutePath = {
183+
val outputDirectory = config.outPrefix match {
184+
case None =>
185+
file.outputDirectory
186+
case Some(prefix) =>
187+
// This is needed for Docusaurus that requires assets (non markdown) files to live under
188+
// `docs/assets/`: https://docusaurus.io/docs/en/doc-markdown#linking-to-images-and-other-assets
189+
file.outputDirectory.resolve(prefix)
168190
}
191+
outputDirectory.resolve(file.relpath).resolveSibling(_ + ".js")
169192
}
170193

171194
override def process(ctx: PreModifierContext): String = {

mdoc-sbt/src/main/scala/mdoc/MdocPlugin.scala

+4-3
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ object MdocPlugin extends AutoPlugin {
1818
)
1919
val mdocIn =
2020
settingKey[File](
21-
"Input directory containing markdown sources to be processed by mdoc. " +
21+
"Input directory or source file containing markdown to be processed by mdoc. " +
2222
"Defaults to the toplevel docs/ directory."
2323
)
2424
val mdocOut =
2525
settingKey[File](
26-
"Output directory for mdoc generated markdown. " +
27-
"Defaults to the target/mdoc directory of this project."
26+
"Output directory or output file name for mdoc generated markdown. " +
27+
"Defaults to the target/mdoc directory of this project. " +
28+
"If this is a file name, it assumes your `in` was also an individual file"
2829
)
2930
val mdocExtraArguments =
3031
settingKey[Seq[String]](

mdoc/src/main/scala/mdoc/MainSettings.scala

+8-2
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,16 @@ final class MainSettings private (
4444
copy(settings.withWorkingDirectory(AbsolutePath(cwd)))
4545
}
4646
def withOut(out: Path): MainSettings = {
47-
copy(settings.copy(out = AbsolutePath(out)))
47+
withOutputPaths(List(out))
48+
}
49+
def withOutputPaths(out: List[Path]): MainSettings = {
50+
copy(settings.copy(out = out.map(AbsolutePath(_)(settings.cwd))))
4851
}
4952
def withIn(in: Path): MainSettings = {
50-
copy(settings.copy(in = AbsolutePath(in)))
53+
withInputPaths(List(in))
54+
}
55+
def withInputPaths(in: List[Path]): MainSettings = {
56+
copy(settings.copy(in = in.map(AbsolutePath(_)(settings.cwd))))
5157
}
5258
def withClasspath(classpath: String): MainSettings = {
5359
copy(settings.copy(classpath = classpath))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package mdoc
2+
3+
import mdoc.internal.cli.Settings
4+
5+
final class OnLoadContext private[mdoc] (
6+
val reporter: Reporter,
7+
private[mdoc] val settings: Settings
8+
) {
9+
def site: Map[String, String] = settings.site
10+
}

mdoc/src/main/scala/mdoc/PostModifier.scala

+7-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import scala.meta.inputs.Input
1010
import scala.meta.io.AbsolutePath
1111
import scala.collection.JavaConverters._
1212
import scala.meta.io.RelativePath
13+
import mdoc.internal.cli.InputFile
1314

1415
trait PostModifier {
1516
val name: String
@@ -33,12 +34,13 @@ final class PostModifierContext private[mdoc] (
3334
val outputCode: String,
3435
val variables: List[Variable],
3536
val reporter: Reporter,
36-
val relativePath: RelativePath,
37+
private[mdoc] val file: InputFile,
3738
private[mdoc] val settings: Settings
3839
) {
39-
def inputFile: AbsolutePath = inDirectory.resolve(relativePath)
40-
def outputFile: AbsolutePath = outDirectory.resolve(relativePath)
4140
def lastValue: Any = variables.lastOption.map(_.runtimeValue).orNull
42-
def inDirectory: AbsolutePath = settings.in
43-
def outDirectory: AbsolutePath = settings.out
41+
def relativePath: RelativePath = file.relpath
42+
def inputFile: AbsolutePath = file.inputFile
43+
def outputFile: AbsolutePath = file.outputFile
44+
def inDirectory: AbsolutePath = file.inputDirectory
45+
def outDirectory: AbsolutePath = file.outputDirectory
4446
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package mdoc
2+
3+
import scala.meta.io.AbsolutePath
4+
import scala.meta.io.RelativePath
5+
import mdoc.internal.cli.Settings
6+
import mdoc.internal.cli.InputFile
7+
8+
final class PostProcessContext private[mdoc] (
9+
val reporter: Reporter,
10+
private[mdoc] val file: InputFile,
11+
private[mdoc] val settings: Settings
12+
) {
13+
def relativePath: RelativePath = file.relpath
14+
def inputFile: AbsolutePath = file.inputFile
15+
def outputFile: AbsolutePath = file.outputFile
16+
def inDirectory: AbsolutePath = file.inputDirectory
17+
def outDirectory: AbsolutePath = file.outputDirectory
18+
}

mdoc/src/main/scala/mdoc/PreModifier.scala

-37
Original file line numberDiff line numberDiff line change
@@ -30,40 +30,3 @@ object PreModifier {
3030
implicit val encoder: ConfEncoder[PreModifier] =
3131
ConfEncoder.StringEncoder.contramap(mod => s"<${mod.name}>")
3232
}
33-
34-
final class OnLoadContext private[mdoc] (
35-
val reporter: Reporter,
36-
private[mdoc] val settings: Settings
37-
) {
38-
def site: Map[String, String] = settings.site
39-
}
40-
41-
final class PostProcessContext private[mdoc] (
42-
val reporter: Reporter,
43-
val relativePath: RelativePath,
44-
private[mdoc] val settings: Settings
45-
) {
46-
def inputFile: AbsolutePath = inDirectory.resolve(relativePath)
47-
def outputFile: AbsolutePath = outDirectory.resolve(relativePath)
48-
def inDirectory: AbsolutePath = settings.in
49-
def outDirectory: AbsolutePath = settings.out
50-
}
51-
52-
final class PreModifierContext private[mdoc] (
53-
val info: String,
54-
val originalCode: Input,
55-
val reporter: Reporter,
56-
val relativePath: RelativePath,
57-
private[mdoc] val settings: Settings
58-
) {
59-
def infoInput: Input = {
60-
val cpos = originalCode.toPosition.toUnslicedPosition
61-
val start = cpos.start - info.length - 1
62-
val end = cpos.start - 1
63-
Input.Slice(cpos.input, start, end)
64-
}
65-
def inputFile: AbsolutePath = inDirectory.resolve(relativePath)
66-
def outputFile: AbsolutePath = outDirectory.resolve(relativePath)
67-
def inDirectory: AbsolutePath = settings.in
68-
def outDirectory: AbsolutePath = settings.out
69-
}

0 commit comments

Comments
 (0)