Skip to content
This repository has been archived by the owner on Jul 16, 2024. It is now read-only.

Commit

Permalink
add confirm prompt to run command after wizard
Browse files Browse the repository at this point in the history
  • Loading branch information
IMax153 committed Nov 30, 2023
1 parent 25bf4db commit ec11670
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 39 deletions.
64 changes: 33 additions & 31 deletions src/internal/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -610,37 +610,39 @@ const validateInternal = (
}
case "Single": {
return Effect.suspend(() => {
if (ReadonlyArray.isNonEmptyReadonlyArray(args)) {
const head = ReadonlyArray.headNonEmpty(args)
const tail = ReadonlyArray.tailNonEmpty(args)
return InternalPrimitive.validate(self.primitiveType, Option.some(head), config).pipe(
Effect.mapBoth({
onFailure: (text) => InternalValidationError.invalidArgument(InternalHelpDoc.p(text)),
onSuccess: (a) => [tail, a] as [ReadonlyArray<string>, any]
})
)
}
const choices = InternalPrimitive.getChoices(self.primitiveType)
if (Option.isSome(self.pseudoName) && Option.isSome(choices)) {
return Effect.fail(InternalValidationError.missingValue(InternalHelpDoc.p(
`Missing argument <${self.pseudoName.value}> with choices ${choices.value}`
)))
}
if (Option.isSome(self.pseudoName)) {
return Effect.fail(InternalValidationError.missingValue(InternalHelpDoc.p(
`Missing argument <${self.pseudoName.value}>`
)))
}
if (Option.isSome(choices)) {
return Effect.fail(InternalValidationError.missingValue(InternalHelpDoc.p(
`Missing argument ${
InternalPrimitive.getTypeName(self.primitiveType)
} with choices ${choices.value}`
)))
}
return Effect.fail(InternalValidationError.missingValue(InternalHelpDoc.p(
`Missing argument ${InternalPrimitive.getTypeName(self.primitiveType)}`
)))
return ReadonlyArray.matchLeft(args, {
onEmpty: () => {
const choices = InternalPrimitive.getChoices(self.primitiveType)
if (Option.isSome(self.pseudoName) && Option.isSome(choices)) {
return Effect.fail(InternalValidationError.missingValue(InternalHelpDoc.p(
`Missing argument <${self.pseudoName.value}> with choices ${choices.value}`
)))
}
if (Option.isSome(self.pseudoName)) {
return Effect.fail(InternalValidationError.missingValue(InternalHelpDoc.p(
`Missing argument <${self.pseudoName.value}>`
)))
}
if (Option.isSome(choices)) {
return Effect.fail(InternalValidationError.missingValue(InternalHelpDoc.p(
`Missing argument ${
InternalPrimitive.getTypeName(self.primitiveType)
} with choices ${choices.value}`
)))
}
return Effect.fail(InternalValidationError.missingValue(InternalHelpDoc.p(
`Missing argument ${InternalPrimitive.getTypeName(self.primitiveType)}`
)))
},
onNonEmpty: (head, tail) =>
InternalPrimitive.validate(self.primitiveType, Option.some(head), config).pipe(
Effect.mapBoth({
onFailure: (text) =>
InternalValidationError.invalidArgument(InternalHelpDoc.p(text)),
onSuccess: (a) => [tail, a] as [ReadonlyArray<string>, any]
})
)
})
})
}
case "Map": {
Expand Down
37 changes: 29 additions & 8 deletions src/internal/cliApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import * as InternalCliConfig from "./cliConfig.js"
import * as InternalCommand from "./commandDescriptor.js"
import * as InternalHelpDoc from "./helpDoc.js"
import * as InternalSpan from "./helpDoc/span.js"
import * as InternalTogglePrompt from "./prompt/toggle.js"
import * as InternalUsage from "./usage.js"
import * as InternalValidationError from "./validationError.js"

Expand Down Expand Up @@ -89,13 +90,13 @@ export const run = dual<
Effect.catchSome((e) =>
InternalValidationError.isValidationError(e) &&
InternalValidationError.isHelpRequested(e)
? Option.some(handleBuiltInOption(self, e.showHelp, config))
? Option.some(handleBuiltInOption(self, e.showHelp, execute, config))
: Option.none()
)
)
}
case "BuiltIn": {
return handleBuiltInOption(self, directive.option, config).pipe(
return handleBuiltInOption(self, directive.option, execute, config).pipe(
Effect.catchSome((e) =>
InternalValidationError.isValidationError(e)
? Option.some(Effect.zipRight(printDocs(e.error), Effect.fail(e)))
Expand All @@ -115,13 +116,18 @@ export const run = dual<
const printDocs = (error: HelpDoc.HelpDoc): Effect.Effect<never, never, void> =>
Console.log(InternalHelpDoc.toAnsiText(error))

const handleBuiltInOption = <A>(
// TODO: move to `/platform`
const isQuitException = (u: unknown): u is Terminal.QuitException =>
typeof u === "object" && u != null && "_tag" in u && u._tag === "QuitException"

const handleBuiltInOption = <R, E, A>(
self: CliApp.CliApp<A>,
builtIn: BuiltInOptions.BuiltInOptions,
execute: (a: A) => Effect.Effect<R, E, void>,
config: CliConfig.CliConfig
): Effect.Effect<
CliApp.CliApp.Environment | Terminal.Terminal,
ValidationError.ValidationError,
R | CliApp.CliApp.Environment | Terminal.Terminal,
E | ValidationError.ValidationError,
void
> => {
switch (builtIn._tag) {
Expand Down Expand Up @@ -225,9 +231,24 @@ const handleBuiltInOption = <A>(
return Console.log(text).pipe(
Effect.zipRight(InternalCommand.wizard(builtIn.command, programName, config)),
Effect.tap((args) => Console.log(InternalHelpDoc.toAnsiText(renderWizardArgs(args)))),
Effect.catchTag("QuitException", () => {
const message = InternalHelpDoc.p(InternalSpan.error("\n\nQuitting wizard mode..."))
return Console.log(InternalHelpDoc.toAnsiText(message))
Effect.flatMap((args) =>
InternalTogglePrompt.toggle({
message: "Would you like to run the command?",
initial: true,
active: "yes",
inactive: "no"
}).pipe(Effect.flatMap((shouldRunCommand) =>
shouldRunCommand
? Console.log().pipe(Effect.zipRight(run(self, args.slice(1), execute)))
: Effect.unit
))
),
Effect.catchAll((e) => {
if (isQuitException(e)) {
const message = InternalHelpDoc.p(InternalSpan.error("\n\nQuitting wizard mode..."))
return Console.log(InternalHelpDoc.toAnsiText(message))
}
return Effect.fail(e)
})
)
}
Expand Down

0 comments on commit ec11670

Please sign in to comment.