Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package scala.cli.commands.shared
import caseapp.*
import caseapp.core.Scala3Helpers.*
import caseapp.core.parser.{Argument, ConsParser, NilParser, StandardArgument}
import caseapp.core.util.Formatter
import caseapp.core.{Arg, Error}
import com.github.plokhotnyuk.jsoniter_scala.core.*
import com.github.plokhotnyuk.jsoniter_scala.macros.*
import scala.cli.commands.tags
// format: off
final case class ScalacOptions(
@Recurse
argsFiles: List[ArgFileOption] = Nil,
@Group(HelpGroup.Scala.toString)
@HelpMessage("Add a scalac option")
@ValueDescription("option")
@Name("O")
@Name("scala-opt")
@Name("scala-option")
@Tag(tags.must)
scalacOption: List[String] = Nil,
)
// format: on
object ScalacOptions {
private val scalacOptionsArg = Arg("scalacOption").copy(
extraNames = Seq(Name("scala-opt"), Name("O"), Name("scala-option")),
valueDescription = Some(ValueDescription("option")),
helpMessage = Some(HelpMessage(
"Add a `scalac` option. Note that options starting with `-g`, `-language`, `-opt`, `-P`, `-target`, `-V`, `-W`, `-X`, and `-Y` are assumed to be Scala compiler options and don't require to be passed after `-O` or `--scalac-option`."
)),
group = Some(Group("Scala")),
origin = Some("ScalacOptions")
)
// .withIsFlag(true) // The scalac options we handle accept no value after the -… argument
val YScriptRunnerOption = "-Yscriptrunner"
private val scalacOptionsPurePrefixes =
Set("-V", "-W", "-X", "-Y")
private val scalacOptionsPrefixes =
Set("-g", "-language", "-opt", "-P", "-target", "-source") ++ scalacOptionsPurePrefixes
private val scalacAliasedOptions = // these options don't require being passed after -O and accept an arg
Set("-encoding", "-release", "-color", YScriptRunnerOption)
private val scalacNoArgAliasedOptions = // these options don't require being passed after -O and don't accept an arg
Set(
"-unchecked",
"-nowarn",
"-feature",
"-deprecation",
"-rewrite",
"-old-syntax",
"-new-syntax",
"-indent",
"-no-indent"
)
/** This includes all the scalac options which disregard inputs and print a help and/or context
* message instead.
*/
val ScalacPrintOptions: Set[String] =
scalacOptionsPurePrefixes ++ Set(
"-help",
"-opt:help",
"-Xshow-phases",
"-Xsource:help",
"-Xplugin-list",
"-Xmixin-force-forwarders:help",
"-Xlint:help",
"-Vphases"
)
/** This includes all the scalac options which are redirected to native Scala CLI options. */
val ScalaCliRedirectedOptions = Set(
"-classpath",
"-cp", // redirected to --extra-jars
"-d" // redirected to --compilation-output
)
val ScalacDeprecatedOptions: Set[String] = Set(
YScriptRunnerOption // old 'scala' runner specific, no longer supported
)
private val scalacOptionsArgument: Argument[List[String]] =
new Argument[List[String]] {
val underlying: StandardArgument[List[String]] = StandardArgument(scalacOptionsArg)
val arg: Arg = scalacOptionsArg
def withDefaultOrigin(origin: String): Argument[List[String]] = this
def init: Option[List[String]] = Some(Nil)
def step(
args: List[String],
index: Int,
acc: Option[List[String]],
formatter: Formatter[Name]
): Either[(Error, List[String]), Option[(Option[List[String]], List[String])]] =
args match {
case h :: t
if scalacOptionsPrefixes.exists(h.startsWith) &&
!ScalacDeprecatedOptions.contains(h) =>
Right(Some((Some(h :: acc.getOrElse(Nil)), t)))
case h :: t if scalacNoArgAliasedOptions.contains(h) =>
Right(Some((Some(h :: acc.getOrElse(Nil)), t)))
case h :: t if scalacAliasedOptions.contains(h) =>
// check if the next scalac arg is a different option or a param to the current option
val maybeOptionArg = t.headOption.filter(!_.startsWith("-"))
// if it's a param, it'll be treated as such and considered already parsed
val newTail = maybeOptionArg.map(_ => t.drop(1)).getOrElse(t)
val newHead = List(h) ++ maybeOptionArg
Right(Some((Some(newHead ++ acc.getOrElse(Nil)), newTail)))
case _ => underlying.step(args, index, acc, formatter)
}
def get(acc: Option[List[String]], formatter: Formatter[Name]): Either[Error, List[String]] =
Right(acc.getOrElse(Nil))
}
implicit lazy val parser: Parser[ScalacOptions] = {
val baseParser = scalacOptionsArgument :: NilParser
implicit val p = ArgFileOption.parser
baseParser.addAll[List[ArgFileOption]].to[ScalacOptions]
}
implicit lazy val help: Help[ScalacOptions] = Help.derive
implicit lazy val jsonCodec: JsonValueCodec[ScalacOptions] = JsonCodecMaker.make
}
case class ArgFileOption(file: String) extends AnyVal
object ArgFileOption {
val arg = Arg(
name = Name("args-file"),
valueDescription = Some(ValueDescription("@arguments-file")),
helpMessage = Some(HelpMessage("File with scalac options.")),
group = Some(Group("Scala")),
origin = Some("ScalacOptions")
)
implicit lazy val parser: Parser[List[ArgFileOption]] = new Parser[List[ArgFileOption]] {
type D = List[ArgFileOption] *: EmptyTuple
override def withDefaultOrigin(origin: String): Parser[List[ArgFileOption]] = this
override def init: D = Nil *: EmptyTuple
override def step(args: List[String], index: Int, d: D, nameFormatter: Formatter[Name])
: Either[(core.Error, Arg, List[String]), Option[(D, Arg, List[String])]] =
args match
case head :: rest if head.startsWith("@") =>
val newD = (ArgFileOption(head.stripPrefix("@")) :: d._1) *: EmptyTuple
Right(Some(newD, arg, rest))
case _ => Right(None)
override def get(
d: D,
nameFormatter: Formatter[Name]
): Either[core.Error, List[ArgFileOption]] = Right(d.head)
override def args: Seq[Arg] = Seq(arg)
}
}