Skip to content

Commit a9a55ac

Browse files
committed
Migrate scala3doc to compiler's parser
1 parent ed764f2 commit a9a55ac

File tree

3 files changed

+104
-105
lines changed

3 files changed

+104
-105
lines changed

compiler/src/dotty/tools/dotc/config/Settings.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ object Settings {
234234
*
235235
* to get their arguments.
236236
*/
237-
protected[config] def processArguments(state: ArgsSummary, processAll: Boolean, skipped: List[String]): ArgsSummary = {
237+
protected def processArguments(state: ArgsSummary, processAll: Boolean, skipped: List[String]): ArgsSummary = {
238238
def stateWithArgs(args: List[String]) = ArgsSummary(state.sstate, args, state.errors, state.warnings)
239239
state.arguments match {
240240
case Nil =>
@@ -269,8 +269,8 @@ object Settings {
269269
def BooleanSetting(name: String, descr: String, initialValue: Boolean = false): Setting[Boolean] =
270270
publish(Setting(name, descr, initialValue))
271271

272-
def StringSetting(name: String, helpArg: String, descr: String, default: String): Setting[String] =
273-
publish(Setting(name, descr, default, helpArg))
272+
def StringSetting(name: String, helpArg: String, descr: String, default: String, aliases: List[String] = Nil): Setting[String] =
273+
publish(Setting(name, descr, default, helpArg, aliases = aliases))
274274

275275
def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String): Setting[String] =
276276
publish(Setting(name, descr, default, helpArg, choices))

scala3doc/src/dotty/dokka/Main.scala

Lines changed: 93 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -12,66 +12,93 @@ import collection.immutable.ArraySeq
1212
import scala.tasty.inspector.TastyInspector
1313
import java.nio.file.Files
1414

15-
import org.kohsuke.args4j.{CmdLineParser, Option => COption}
16-
import org.kohsuke.args4j.spi.StringArrayOptionHandler
17-
18-
class RawArgs:
19-
@COption(name="--tastyRoots", required = true, aliases = Array("-t"), usage="Roots where tools should look for tasty files")
20-
protected var tastyRoots: String = null
21-
22-
@COption(name="--dest",required = true, aliases = Array("-d"), usage="Output to generate documentation to")
23-
protected var output: String = "output"
24-
25-
@COption(name="--classpath", aliases = Array("--cp", "-c"), usage="Classpath to load dependencies from")
26-
protected var classpath: String = System.getProperty("java.class.path")
27-
28-
@COption(name="--name", required = true, aliases = Array("-n"), usage="Name of module in generated documentation")
29-
protected var name: String = "main"
30-
31-
@COption(name="--docs", aliases = Array("-p"), usage="Root of project docs")
32-
private var docsRoot: String = null
33-
34-
@COption(name="--sources", handler = classOf[StringArrayOptionHandler], aliases = Array("-s"), usage = "Links to source files provided in convention: local_directory=remote_directory#line_suffix")
35-
private var sourceLinks: JList[String] = null
36-
37-
@COption(name="--projectTitle")
38-
protected var projectTitle: String = null
39-
40-
@COption(name="--projectVersion")
41-
protected var projectVersion: String = null
42-
43-
@COption(name="--projectLogo")
44-
protected var projectLogo: String = null
45-
46-
@COption(name="--syntax")
47-
protected var syntax: String = null
48-
49-
@COption(name="--revision")
50-
protected var revision: String = null
51-
52-
def toArgs =
53-
val parsedSyntax = syntax match
54-
case null => None
55-
case other =>
56-
Args.CommentSyntax.fromString(other) match
57-
case None =>
58-
sys.error(s"unrecognized value for --syntax option: $other")
59-
case some => some
60-
61-
Args(
62-
name,
63-
tastyRoots.split(File.pathSeparatorChar).toList.map(new File(_)),
64-
classpath,
65-
new File(output),
66-
Option(docsRoot),
67-
Option(projectVersion),
68-
Option(projectTitle),
69-
Option(projectLogo),
70-
parsedSyntax,
71-
Option(sourceLinks).map(_.asScala.toList).getOrElse(List.empty),
72-
Option(revision)
73-
)
74-
15+
import dotty.tools.dotc.config.Settings._
16+
17+
abstract class Scala3Args extends SettingGroup:
18+
val tastyRoots: Setting[String] =
19+
StringSetting("--tastyRoots", "tastyRoots", "Roots where tools should look for tasty files", "", aliases = List("-t"))
20+
val tastyRootsAlias: Setting[String] =
21+
StringSetting("-t", "tastyRoots", "Roots where tools should look for tasty files", "", aliases = List("-t"))
22+
23+
val dest: Setting[String] =
24+
StringSetting("--dest", "dest", "Output to generate documentation to", "", aliases = List("-d"))
25+
val destAlias: Setting[String] =
26+
StringSetting("-d", "dest", "Output to generate documentation to", "")
27+
28+
val classpath: Setting[String] =
29+
StringSetting("--classpath", "classpath", "Classpath to load dependencies from", "", aliases = List("--cp", "-c"))
30+
val classpathAlias1: Setting[String] =
31+
StringSetting("--cp", "classpath", "Classpath to load dependencies from", "", aliases = List("--cp", "-c"))
32+
val classpathAlias2: Setting[String] =
33+
StringSetting("-c", "classpath", "Classpath to load dependencies from", "", aliases = List("--cp", "-c"))
34+
35+
val name: Setting[String] =
36+
StringSetting("--name", "name", "Name of module in generated documentation", "", aliases = List("-n"))
37+
val nameAlias: Setting[String] =
38+
StringSetting("-n", "name", "Name of module in generated documentation", "")
39+
40+
val docsRoot: Setting[String] =
41+
StringSetting("--docs", "docs", "Root of project docs", "", aliases = List("-p"))
42+
val docsRootAlias: Setting[String] =
43+
StringSetting("-p", "docs", "Root of project docs", "", aliases = List("-p"))
44+
45+
46+
val sourceLinks: Setting[String] =
47+
StringSetting("--sources", "sources", "Links to source files provided in convention: local_directory=remote_directory#line_suffix", "")
48+
val sourceLinksAlias: Setting[String] =
49+
StringSetting("-s", "sources", "Links to source files provided in convention: local_directory=remote_directory#line_suffix", "")
50+
51+
val projectTitle: Setting[String] =
52+
StringSetting("--projectTitle", "projectTitle", "Title of the project used in documentation", "")
53+
54+
val projectVersion: Setting[String] =
55+
StringSetting("--projectVersion", "projectVersion", "Version of the project used in documentation", "")
56+
57+
val projectLogo: Setting[String] =
58+
StringSetting("--projectLogo", "projectLogo", "Relative path to logo of the project", "")
59+
60+
val revision: Setting[String] =
61+
StringSetting("--revision", "revision", "Revision (branch or ref) used to build project project", "")
62+
63+
val syntax: Setting[String] =
64+
StringSetting("--syntax", "syntax", "Syntax of the comment used", "")
65+
66+
protected def defaultName(): String
67+
protected def defaultTastFiles(): List[File]
68+
protected def defaultDest(): File
69+
70+
def extract(args: List[String]) =
71+
val initialSummary = ArgsSummary(defaultState, args, errors = Nil, warnings = Nil)
72+
val res = processArguments(initialSummary, processAll = true, skipped = Nil)
73+
// TODO!
74+
if res.errors.nonEmpty then sys.error(s"Unable to parse arguments:\n ${res.errors.mkString("\n")}")
75+
76+
val parsedSyntax = syntax.valueIn(res.sstate) match
77+
case "" => None
78+
case other =>
79+
Args.CommentSyntax.fromString(other) match
80+
case None =>
81+
sys.error(s"unrecognized value for --syntax option: $other")
82+
case some => some
83+
84+
def parseOptionalArg(args: Setting[String]*) =
85+
args.map(_.valueIn(res.sstate)).find(_ != "")
86+
87+
def parseTastyRoots(roots: String) = roots.split(File.pathSeparatorChar).toList.map(new File(_))
88+
89+
Args(
90+
parseOptionalArg(name, nameAlias).getOrElse(defaultName()),
91+
parseOptionalArg(tastyRoots, tastyRootsAlias).fold(defaultTastFiles())(parseTastyRoots),
92+
parseOptionalArg(classpath, classpathAlias1, classpathAlias2).getOrElse(System.getProperty("java.class.path")),
93+
parseOptionalArg(dest, destAlias).fold(defaultDest())(new File(_)),
94+
parseOptionalArg(docsRoot, docsRootAlias),
95+
parseOptionalArg(projectVersion),
96+
parseOptionalArg(projectTitle),
97+
parseOptionalArg(projectLogo),
98+
parsedSyntax,
99+
parseOptionalArg(sourceLinks, sourceLinksAlias).fold(Nil)(_.split(",").toList), // TODO!
100+
parseOptionalArg(revision)
101+
)
75102

76103
case class Args(
77104
name: String,
@@ -150,9 +177,12 @@ object Main:
150177
sys.exit(1)
151178

152179
def main(args: Array[String]): Unit =
153-
val rawArgs = new RawArgs
154-
new CmdLineParser(rawArgs).parseArgument(args:_*)
155-
main(rawArgs.toArgs)
180+
val argDefinition = new Scala3Args {
181+
protected def defaultName(): String = sys.error(s"Argument '${name.name}' is required")
182+
protected def defaultTastFiles(): List[File] = sys.error(s"Argument '${tastyRoots.name}' is required")
183+
protected def defaultDest(): File = sys.error(s"Argument '${dest.name}' is required")
184+
}
185+
main(argDefinition.extract(args.toList))
156186
// Sometimes jvm is hanging, so we want to be sure that we force shout down the jvm
157187
sys.exit(0)
158188

scala3doc/src/dotty/tools/dottydoc/Main.scala

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package dotty.tools
22
package dottydoc
33

4-
import dotty.dokka.{Args, RawArgs, DocConfiguration, DottyDokkaConfig}
4+
import dotty.dokka.{Args, DocConfiguration, DottyDokkaConfig, Scala3Args}
55

66
import org.jetbrains.dokka._
77
import org.jetbrains.dokka.utilities._
@@ -32,49 +32,18 @@ object Main extends Driver {
3232
* how they're split).
3333
*/
3434
override def process(args: Array[String], rootCtx: Context): Reporter = {
35-
// split args into ours and Dotty's
36-
val (dokkaStrArgs, compilerArgs) = {
37-
args.partitionMap { arg =>
38-
// our options start with this magic prefix, inserted by the SBT plugin
39-
val magicPrefix = "--+DOC+"
40-
if arg startsWith magicPrefix then
41-
Left(arg stripPrefix magicPrefix)
42-
else
43-
Right(arg)
44-
}
45-
}
4635

47-
val (filesToCompile, ctx) = setup(compilerArgs, rootCtx)
48-
given Context = ctx
4936

50-
// parse Dokka args
51-
// note: all required args should be set with SBT settings,
52-
// to make it easier to set and override them
53-
val dokkaArgs = {
54-
val dokkaRawArgs = new RawArgs
55-
val requiredArgs = Seq(
56-
"--tastyRoots", "", // hack, value is not used in SBT but required in CLI
57-
// we extract some settings from Dotty options since that's how SBT passes them
58-
"--name", ctx.settings.projectName.value,
59-
"--projectTitle", ctx.settings.projectName.value,
60-
"--dest", ctx.settings.outputDir.value.toString,
61-
)
37+
val (filesToCompile, ctx) = setup(args, rootCtx)
38+
given Context = ctx
6239

63-
val allArgs = requiredArgs ++ dokkaStrArgs
64-
println(s"Running scala3doc with arguments: $allArgs")
65-
val parser = org.kohsuke.args4j.CmdLineParser(dokkaRawArgs)
66-
try {
67-
parser.parseArgument(allArgs : _*)
68-
} catch {
69-
case ex: org.kohsuke.args4j.CmdLineException =>
70-
// compiler errors are reported in SBT
71-
dotc.report.error(s"Error when parsing Scala3doc options: ${ex.getMessage}")
72-
throw ex
73-
}
74-
dokkaRawArgs.toArgs
40+
val argDefinition = new Scala3Args() {
41+
protected def defaultName(): String = ctx.settings.projectName.value
42+
protected def defaultTastFiles(): List[File] = Nil
43+
protected def defaultDest(): File = File(ctx.settings.outputDir.value.toString)
7544
}
7645

77-
val config = DocConfiguration.Sbt(dokkaArgs, filesToCompile, ctx)
46+
val config = DocConfiguration.Sbt(argDefinition.extract(args.toList), filesToCompile, ctx)
7847
val dokkaCfg = new DottyDokkaConfig(config)
7948
new DokkaGenerator(dokkaCfg, DokkaConsoleLogger.INSTANCE).generate()
8049

0 commit comments

Comments
 (0)