Skip to content

Commit

Permalink
Merge pull request #548 from alexarchambault/nit
Browse files Browse the repository at this point in the history
Tweak many things
  • Loading branch information
alexarchambault authored Jun 14, 2024
2 parents 950c9da + 49c6aab commit 6e6a78b
Show file tree
Hide file tree
Showing 26 changed files with 258 additions and 143 deletions.
19 changes: 2 additions & 17 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -84,33 +84,18 @@ object core extends Module {
annotations.jvm(),
util.jvm()
)

object test extends Tests with TestCrossSources {
def ivyDeps = Agg(Deps.utest)
def testFramework = "utest.runner.Framework"
}
}
trait CoreJs extends Core with CaseAppScalaJsModule with MimaChecks {
def moduleDeps = Seq(
annotations.js(),
util.js()
)

object test extends SbtModuleTests with ScalaJSTests with TestCrossSources {
def ivyDeps = Agg(Deps.utest)
def testFramework = "utest.runner.Framework"
}
}
trait CoreNative extends Core with CaseAppScalaNativeModule {
def moduleDeps = Seq(
annotations.native(),
util.native()
)

object test extends SbtModuleTests with ScalaNativeTests with TestCrossSources {
def ivyDeps = Agg(Deps.utest)
def testFramework = "utest.runner.Framework"
}
}

trait Core extends CrossSbtModule with CrossSources with CaseAppPublishModule {
Expand Down Expand Up @@ -171,7 +156,7 @@ object cats2 extends Module {

trait Cats2Jvm extends Cats2 with MimaChecks {
def moduleDeps = Seq(core.jvm())
def sources = cats.jvm().sources()
def sources = T.sources(cats.jvm().sources())

object test extends Tests with TestCrossSources {
def ivyDeps = Agg(Deps.utest)
Expand All @@ -180,7 +165,7 @@ object cats2 extends Module {
}
trait Cats2Js extends Cats2 with CaseAppScalaJsModule with MimaChecks {
def moduleDeps = Seq(core.js())
def sources = cats.js().sources()
def sources = T.sources(cats.js().sources())

object test extends SbtModuleTests with ScalaJSTests with TestCrossSources {
def ivyDeps = Agg(Deps.utest)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package caseapp.cats
package caseapp.catseffect

import caseapp.core.Error
import caseapp.core.help.{Help, WithHelp}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package caseapp.cats
package caseapp

import caseapp.core.argparser.{AccumulatorArgParser, ArgParser}
import cats.data.NonEmptyList

object CatsArgParser {
package object catseffect {
implicit def nonEmptyListArgParser[T](
implicit parser: ArgParser[T]
): AccumulatorArgParser[NonEmptyList[T]] =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package caseapp.cats
package caseapp.catseffect

import _root_.cats.effect._
import _root_.cats.effect.unsafe.implicits.global
import _root_.cats.data.NonEmptyList
import cats.effect._
import cats.effect.unsafe.implicits.global
import cats.data.NonEmptyList
import caseapp._
import caseapp.core.help.Help
import caseapp.core.Error
import utest._

import caseapp.cats.CatsArgParser._

sealed trait RecordedApp {

val stdoutBuff: Ref[IO, List[String]] = Ref.unsafe(List.empty)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package caseapp
package cats
package catseffect

import _root_.cats.data.NonEmptyList
import cats.data.NonEmptyList

object Definitions {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package caseapp.cats
package caseapp.catseffect

import _root_.cats.effect._
import _root_.cats.effect.concurrent.Ref
import _root_.cats.implicits._
import _root_.cats.data.NonEmptyList
import cats.effect._
import cats.effect.concurrent.Ref
import cats.implicits._
import cats.data.NonEmptyList
import caseapp._
import caseapp.core.help.Help
import caseapp.core.Error
import utest._

import caseapp.cats.CatsArgParser._

sealed trait RecordedApp {

val stdoutBuff: Ref[IO, List[String]] = Ref.unsafe(List.empty)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package caseapp
package cats
package catseffect

import _root_.cats.data.NonEmptyList
import cats.data.NonEmptyList

object Definitions {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package caseapp.core.app

import caseapp.core.complete.{Bash, Fish, Zsh}
import caseapp.core.complete.{
Bash,
CompletionsInstallOptions,
CompletionsUninstallOptions,
Fish,
Zsh
}

import java.io.File
import java.nio.charset.{Charset, StandardCharsets}
Expand All @@ -21,7 +27,7 @@ trait PlatformCommandsMethods { self: CommandsEntryPoint =>

// Adapted from https://github.com/VirtusLab/scala-cli/blob/eced0b35c769eca58ae6f1b1a3be0f29a8700859/modules/cli/src/main/scala/scala/cli/commands/installcompletions/InstallCompletions.scala
def completionsInstall(completionsWorkingDirectory: String, args: Seq[String]): Unit = {
val (options, rem) = CaseApp.process[PlatformCommandsMethods.CompletionsInstallOptions](args)
val (options, rem) = CaseApp.process[CompletionsInstallOptions](args)

lazy val completionsDir = Paths.get(options.output.getOrElse(completionsWorkingDirectory))

Expand Down Expand Up @@ -128,7 +134,7 @@ trait PlatformCommandsMethods { self: CommandsEntryPoint =>
}

def completionsUninstall(completionsWorkingDirectory: String, args: Seq[String]): Unit = {
val (options, rem) = CaseApp.process[PlatformCommandsMethods.CompletionsUninstallOptions](args)
val (options, rem) = CaseApp.process[CompletionsUninstallOptions](args)

val name = options.name.getOrElse(Paths.get(progName).getFileName.toString)

Expand Down Expand Up @@ -164,55 +170,6 @@ trait PlatformCommandsMethods { self: CommandsEntryPoint =>
}

object PlatformCommandsMethods {
import caseapp.{HelpMessage, Name}
import caseapp.core.help.Help
import caseapp.core.parser.Parser

// from https://github.com/VirtusLab/scala-cli/blob/eced0b35c769eca58ae6f1b1a3be0f29a8700859/modules/cli/src/main/scala/scala/cli/commands/installcompletions/InstallCompletionsOptions.scala
// format: off
final case class CompletionsInstallOptions(
@HelpMessage("Print completions to stdout")
env: Boolean = false,
@HelpMessage("Custom completions name")
name: Option[String] = None,
@HelpMessage("Name of the shell, either zsh, fish or bash")
@Name("shell")
format: Option[String] = None,
@HelpMessage("Completions output directory (defaults to $XDG_CONFIG_HOME/fish/completions on fish)")
@Name("o")
output: Option[String] = None,
@HelpMessage("Custom banner in comment placed in rc file (bash or zsh only)")
banner: String = "{NAME} completions",
@HelpMessage("Path to `*rc` file, defaults to `.bashrc` or `.zshrc` depending on shell (bash or zsh only)")
rcFile: Option[String] = None
)
// format: on

object CompletionsInstallOptions {
implicit lazy val parser: Parser[CompletionsInstallOptions] = Parser.derive
implicit lazy val help: Help[CompletionsInstallOptions] = Help.derive
}

// from https://github.com/VirtusLab/scala-cli/blob/eced0b35c769eca58ae6f1b1a3be0f29a8700859/modules/cli/src/main/scala/scala/cli/commands/uninstallcompletions/SharedUninstallCompletionsOptions.scala
// format: off
final case class CompletionsUninstallOptions(
@HelpMessage("Path to `*rc` file, defaults to `.bashrc` or `.zshrc` depending on shell (bash or zsh only)")
rcFile: Option[String] = None,
@HelpMessage("Custom banner in comment placed in rc file")
banner: String = "{NAME} completions",
@HelpMessage("Custom completions name")
name: Option[String] = None,
@HelpMessage("Completions output directory (defaults to $XDG_CONFIG_HOME/fish/completions on fish)")
@Name("o")
output: Option[String] = None,
)
// format: on

object CompletionsUninstallOptions {
implicit lazy val parser: Parser[CompletionsUninstallOptions] = Parser.derive
implicit lazy val help: Help[CompletionsUninstallOptions] = Help.derive
}

def getFormat(format: Option[String]): Option[String] =
format.map(_.trim).filter(_.nonEmpty)
.orElse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ abstract class HelpCompanion {
helpMessage: AnnotationOption[HelpMessage, T]
): Help[T] = {

val appName0 = appName().fold(typeable.describe.stripSuffix("Options"))(_.appName)
val appName0 = appName() match {
case None =>
if (typeable.describe == "Options") typeable.describe
else typeable.describe.stripSuffix("Options")
case Some(name) =>
name.appName
}

Help(
parser.args,
Expand Down
1 change: 1 addition & 0 deletions core/shared/src/main/scala/caseapp/core/Arg.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import dataclass._
def withDefaultOrigin(defaultOrigin: String): Arg =
if (origin.isEmpty) this.withOrigin(Some(defaultOrigin))
else this
lazy val names = name +: extraNames
}

object Arg {
Expand Down
9 changes: 6 additions & 3 deletions core/shared/src/main/scala/caseapp/core/RemainingArgs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ import dataclass.data
indexedUnparsed: Seq[Indexed[String]]
) {

def remaining: Seq[String] = indexedRemaining.map(_.value)
def unparsed: Seq[String] = indexedUnparsed.map(_.value)
lazy val remaining: Seq[String] = indexedRemaining.map(_.value)
lazy val unparsed: Seq[String] = indexedUnparsed.map(_.value)

/** Arguments both before and after a `--`.
*
* The first `--`, if any, is not included in this list.
*/
def all: Seq[String] =
lazy val all: Seq[String] =
remaining ++ unparsed

lazy val indexed: Seq[Indexed[String]] =
indexedRemaining ++ indexedUnparsed
}
17 changes: 13 additions & 4 deletions core/shared/src/main/scala/caseapp/core/app/CaseApp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@ import caseapp.core.util.Formatter

abstract class CaseApp[T](implicit val parser0: Parser[T], val messages: Help[T]) {

def name: String =
help.progName

def hasHelp: Boolean = true
def hasFullHelp: Boolean = false

def help: Help[T] = messages

def parser: Parser[T] = {
val p = parser0.nameFormatter(nameFormatter)
if (ignoreUnrecognized)
Expand Down Expand Up @@ -69,10 +74,14 @@ abstract class CaseApp[T](implicit val parser0: Parser[T], val messages: Help[T]
exit(1)
}

lazy val finalHelp: Help[_] =
if (hasFullHelp) messages.withFullHelp
else if (hasHelp) messages.withHelp
else messages
lazy val finalHelp: Help[_] = {
val h =
if (hasFullHelp) messages.withFullHelp
else if (hasHelp) messages.withHelp
else messages
if (name == h.progName) h
else h.withProgName(name)
}

def fullHelpAsked(progName: String): Nothing = {
val help = if (progName.isEmpty) finalHelp else finalHelp.withProgName(progName)
Expand Down
2 changes: 0 additions & 2 deletions core/shared/src/main/scala/caseapp/core/app/Command.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ abstract class Command[T](implicit parser: Parser[T], help: Help[T])
extends CaseApp()(parser, help) {
def names: List[List[String]] =
List(List(name))
def name: String =
help.progName
def group: String = ""
def hidden: Boolean = false
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,28 @@ abstract class CommandsEntryPoint extends PlatformCommandsMethods {
printLine("", toStderr = true)
}

def completePrintInstructions(toStderr: Boolean): Unit = {
val formats = Seq(Bash.id, Zsh.id, Fish.id)
printLine("To manually get completions, run", toStderr = toStderr)
printLine("", toStderr = toStderr)
printLine(
s" $progName ${completeCommandName.mkString(" ")} ${formats.mkString("|")} index command...",
toStderr = toStderr
)
printLine("", toStderr = toStderr)
printLine(
"where index starts from one, and command... includes the command name, like",
toStderr = toStderr
)
printLine("", toStderr = toStderr)
printLine(
s" $progName ${completeCommandName.mkString(" ")} ${Zsh.id} 2 $progName --",
toStderr = toStderr
)
printLine("", toStderr = toStderr)
printLine("to get completions for '--'", toStderr = toStderr)
}

def completionsPrintUsage(): Nothing = {
completionsPrintInstructions()
exit(1)
Expand All @@ -58,11 +80,6 @@ abstract class CommandsEntryPoint extends PlatformCommandsMethods {
exit(1)
}

def completePrintUsage(): Nothing = {
completionsPrintInstructions()
exit(1)
}

def completionsWorkingDirectory: Option[String] = None

def completionsMain(args: Array[String]): Unit = {
Expand Down Expand Up @@ -122,8 +139,11 @@ abstract class CommandsEntryPoint extends PlatformCommandsMethods {
case _ =>
completeUnrecognizedFormat(format)
}
case Array("--help" | "--usage" | "-h") =>
completePrintInstructions(toStderr = false)
case _ =>
completePrintUsage()
completePrintInstructions(toStderr = true)
exit(1)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ object ArgParser extends PlatformArgParsers {
/** Look for an implicit `ArgParser[T]` */
def apply[T](implicit parser: ArgParser[T]): ArgParser[T] = parser

implicit def byte: ArgParser[Byte] =
SimpleArgParser.byte

implicit def short: ArgParser[Short] =
SimpleArgParser.short

implicit def int: ArgParser[Int] =
SimpleArgParser.int

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ object SimpleArgParser {
def from[T](description: String)(parse: String => Either[Error, T]): SimpleArgParser[T] =
SimpleArgParser(description, (value, _, _) => parse(value))

val byte: SimpleArgParser[Byte] =
from("byte") { s =>
try Right(s.toByte)
catch {
case _: NumberFormatException =>
Left(Error.MalformedValue("byte-sized integer", s))
}
}

val short: SimpleArgParser[Short] =
from("short") { s =>
try Right(s.toShort)
catch {
case _: NumberFormatException =>
Left(Error.MalformedValue("short integer", s))
}
}

val int: SimpleArgParser[Int] =
from("int") { s =>
try Right(s.toInt)
Expand Down
Loading

0 comments on commit 6e6a78b

Please sign in to comment.