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

Commit

Permalink
Implement wizard and completions (#373)
Browse files Browse the repository at this point in the history
  • Loading branch information
IMax153 authored Nov 16, 2023
1 parent b0e85a2 commit e6b790d
Show file tree
Hide file tree
Showing 44 changed files with 3,734 additions and 1,559 deletions.
5 changes: 5 additions & 0 deletions .changeset/calm-doors-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/cli": minor
---

implement `--wizard` mode for cli applications
5 changes: 5 additions & 0 deletions .changeset/clever-waves-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/cli": minor
---

implement completion script generation for cli applications
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ tmp/
build/
dist/
.direnv/
docs/
2 changes: 0 additions & 2 deletions .prettierignore

This file was deleted.

44 changes: 24 additions & 20 deletions examples/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import * as HelpDoc from "@effect/cli/HelpDoc"
import * as Span from "@effect/cli/HelpDoc/Span"
import * as Options from "@effect/cli/Options"
import * as NodeContext from "@effect/platform-node/NodeContext"
import * as Terminal from "@effect/platform-node/Terminal"
import * as Data from "effect/Data"
import * as Effect from "effect/Effect"
import { pipe } from "effect/Function"
import * as Layer from "effect/Layer"
import * as Option from "effect/Option"

export interface Git extends Data.Case {
Expand Down Expand Up @@ -52,41 +53,42 @@ export interface RemoveRemote extends Data.Case {

export const RemoveRemote = Data.tagged<RemoveRemote>("RemoveRemote")

const add: Command.Command<GitSubcommand> = pipe(
Command.standard("add", {
options: Options.boolean("m"),
args: Args.text({ name: "directory" })
}),
const add: Command.Command<GitSubcommand> = Command.standard("add", {
options: Options.boolean("m"),
args: Args.text({ name: "directory" })
}).pipe(
Command.withHelp(HelpDoc.p("Description of the `git add` subcommand")),
Command.map(({ args: directory, options: modified }) => Add({ modified, directory }))
)

const addRemote: Command.Command<RemoteSubcommand> = pipe(
Command.standard("add", {
options: Options.all({
name: Options.text("name"),
url: Options.text("url")
})
}),
const addRemote: Command.Command<RemoteSubcommand> = Command.standard("add", {
options: Options.all({
name: Options.text("name"),
url: Options.text("url")
})
}).pipe(
Command.withHelp(HelpDoc.p("Description of the `git remote add` subcommand")),
Command.map(({ options: { name, url } }) => AddRemote({ name, url }))
)

const removeRemote: Command.Command<RemoteSubcommand> = pipe(
Command.standard("remove", { args: Args.text({ name: "name" }) }),
const removeRemote: Command.Command<RemoteSubcommand> = Command.standard("remove", {
args: Args.text({ name: "name" })
}).pipe(
Command.withHelp(HelpDoc.p("Description of the `git remote remove` subcommand")),
Command.map(({ args: name }) => RemoveRemote({ name }))
)

const remote: Command.Command<GitSubcommand> = pipe(
Command.standard("remote", { options: Options.boolean("verbose").pipe(Options.withAlias("v")) }),
const remote: Command.Command<GitSubcommand> = Command.standard("remote", {
options: Options.boolean("verbose").pipe(Options.withAlias("v"))
}).pipe(
Command.withHelp("Description of the `git remote` subcommand"),
Command.subcommands([addRemote, removeRemote]),
Command.map(({ options: verbose, subcommand }) => Remote({ verbose, subcommand }))
)

const git: Command.Command<Git> = pipe(
Command.standard("git", { options: Options.boolean("version").pipe(Options.withAlias("v")) }),
const git: Command.Command<Git> = Command.standard("git", {
options: Options.boolean("version").pipe(Options.withAlias("v"))
}).pipe(
Command.subcommands([add, remote]),
Command.map(({ options: version, subcommand }) => Git({ version, subcommand }))
)
Expand Down Expand Up @@ -132,6 +134,8 @@ const cli = CliApp.make({
footer: HelpDoc.p("Copyright 2023")
})

const MainLive = Layer.merge(NodeContext.layer, Terminal.layer)

Effect.sync(() => process.argv.slice(2)).pipe(
Effect.flatMap((args) =>
CliApp.run(cli, args, (command) =>
Expand All @@ -143,6 +147,6 @@ Effect.sync(() => process.argv.slice(2)).pipe(
onSome: handleGitSubcommand
}))
),
Effect.provide(NodeContext.layer),
Effect.provide(MainLive),
Effect.runFork
)
61 changes: 48 additions & 13 deletions examples/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,66 @@ import * as CliApp from "@effect/cli/CliApp"
import * as Command from "@effect/cli/Command"
import * as Prompt from "@effect/cli/Prompt"
import * as NodeContext from "@effect/platform-node/NodeContext"
import * as Terminal from "@effect/platform-node/Terminal"
import * as Effect from "effect/Effect"
import * as Layer from "effect/Layer"

const colorPrompt = Prompt.select({
message: "Pick your favorite color!",
choices: [
{ title: "Red", value: "#ff0000", description: "This option has a description" },
{ title: "Green", value: "#00ff00" },
{ title: "Blue", value: "#0000ff" }
]
})
// const colorPrompt = Prompt.select({
// message: "Pick your favorite color",
// choices: [
// { title: "Red", value: "#ff0000", description: "This option has a description" },
// { title: "Green", value: "#00ff00", description: "So does this one" },
// { title: "Blue", value: "#0000ff", disabled: true }
// ]
// })

// const confirmPrompt = Prompt.confirm({
// message: "Can you please confirm?"
// })

// const datePrompt = Prompt.date({
// message: "What's your birth day?",
// dateMask:
// "\"Year:\" YYYY, \"Month:\" MM, \"Day:\" DD \\\\\\\\||// \\Hour: HH, \\Minute: mm, \"Seconds:\" ss",
// validate: (date) =>
// date.getTime() > Date.now()
// ? Effect.fail("Your birth day can't be in the future")
// : Effect.succeed(date)
// })

const numberPrompt = Prompt.float({
message: `What is your favorite number?`
// const numberPrompt = Prompt.float({
// message: `What is your favorite number?`,
// validate: (n) => n > 0 ? Effect.succeed(n) : Effect.fail("must be greater than 0")
// })

// const textPrompt = Prompt.text({
// message: `Please answer the following question\nWhat is your favorite food?`,
// type: "hidden",
// validate: (value) =>
// value.length === 0
// ? Effect.fail("must be non-empty\nyou entered " + value)
// : Effect.succeed(value)
// })

const togglePrompt = Prompt.toggle({
message: "Can you confirm?",
active: "yes",
inactive: "no"
})

const prompt = Prompt.all([colorPrompt, numberPrompt])
// const prompt = Prompt.all([colorPrompt, numberPrompt, textPrompt])

const cli = CliApp.make({
name: "Your Favorite Things",
version: "0.0.1",
command: Command.prompt("favorites", prompt)
// command: Command.prompt("favorites", prompt)
command: Command.prompt("favorites", togglePrompt)
})

const MainLive = Layer.merge(NodeContext.layer, Terminal.layer)

Effect.sync(() => process.argv.slice(2)).pipe(
Effect.flatMap((args) => CliApp.run(cli, args, (input) => Effect.log(input))),
Effect.provide(NodeContext.layer),
Effect.provide(MainLive),
Effect.runFork
)
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"build-esm": "tsc -b tsconfig.build.json",
"build-cjs": "babel build/esm --plugins @babel/transform-export-namespace-from --plugins @babel/transform-modules-commonjs --out-dir build/cjs --source-maps",
"build-annotate": "babel build --plugins annotate-pure-calls --out-dir build --source-maps",
"clean": "rimraf build dist coverage .tsbuildinfo",
"clean": "rimraf build dist docs coverage .tsbuildinfo",
"lint": "eslint src test examples --ext .ts",
"lint-fix": "pnpm lint --fix",
"check": "tsc -b tsconfig.json",
Expand All @@ -70,12 +70,12 @@
"@babel/plugin-transform-modules-commonjs": "^7.23.3",
"@changesets/changelog-github": "^0.4.8",
"@changesets/cli": "^2.26.2",
"@effect/build-utils": "^0.4.1",
"@effect/docgen": "^0.3.2",
"@effect/build-utils": "^0.5.0",
"@effect/docgen": "^0.3.4",
"@effect/eslint-plugin": "^0.1.2",
"@effect/language-service": "^0.0.21",
"@effect/platform": "^0.30.0",
"@effect/platform-node": "^0.31.0",
"@effect/platform": "^0.30.2",
"@effect/platform-node": "^0.31.2",
"@effect/printer": "^0.23.1",
"@effect/printer-ansi": "^0.23.1",
"@effect/schema": "^0.48.0",
Expand All @@ -95,11 +95,11 @@
"eslint-plugin-sort-destructure-keys": "^1.5.0",
"fast-check": "^3.13.2",
"madge": "^6.1.0",
"prettier": "^3.1.0",
"rimraf": "^5.0.5",
"stackframe": "^1.3.4",
"tsx": "^4.1.2",
"typescript": "^5.2.2",
"vite": "^4.5.0",
"vite": "^5.0.0",
"vitest": "^0.34.6"
}
}
Loading

0 comments on commit e6b790d

Please sign in to comment.