pkg/tool/cli: support ask task

Closes #467
https://github.com/cuelang/cue/pull/467

GitOrigin-RevId: 5b68202c3748b256f627f6cb5d0cd239c8650fff
Change-Id: I42bab4558d32fde97c0a861c99cf7bcc2a935aa6
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7261
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/pkg/tool/cli/cli.cue b/pkg/tool/cli/cli.cue
index 6f581f3..562ffa5 100644
--- a/pkg/tool/cli/cli.cue
+++ b/pkg/tool/cli/cli.cue
@@ -22,7 +22,6 @@
 	text: string
 }
 
-// TODO:
 // Ask prompts the current console with a message and waits for input.
 //
 // Example:
@@ -30,13 +29,13 @@
 //         prompt:   "Are you okay?"
 //         repsonse: bool
 //     })
-// Ask: {
-//  kind: "tool/cli.Ask"
+Ask: {
+	kind: "tool/cli.Ask"
 
-//  // prompt sends this message to the output.
-//  prompt: string
+	// prompt sends this message to the output.
+	prompt: string
 
-//  // response holds the user's response. If it is a boolean expression it
-//  // will interpret the answer using textual yes/ no.
-//  response: string | bool
-// }
+	// response holds the user's response. If it is a boolean expression it
+	// will interpret the answer using textual yes/ no.
+	response: string | bool
+}
diff --git a/pkg/tool/cli/cli.go b/pkg/tool/cli/cli.go
index 8ba4878..fbd5c4d 100644
--- a/pkg/tool/cli/cli.go
+++ b/pkg/tool/cli/cli.go
@@ -19,6 +19,7 @@
 
 import (
 	"fmt"
+	"strings"
 
 	"cuelang.org/go/cue"
 	"cuelang.org/go/internal/task"
@@ -26,6 +27,7 @@
 
 func init() {
 	task.Register("tool/cli.Print", newPrintCmd)
+	task.Register("tool/cli.Ask", newAskCmd)
 
 	// For backwards compatibility.
 	task.Register("print", newPrintCmd)
@@ -45,3 +47,39 @@
 	fmt.Fprintln(ctx.Stdout, str)
 	return nil, nil
 }
+
+type askCmd struct{}
+
+func newAskCmd(v cue.Value) (task.Runner, error) {
+	return &askCmd{}, nil
+}
+
+func (c *askCmd) Run(ctx *task.Context) (res interface{}, err error) {
+	str := ctx.String("prompt")
+	if ctx.Err != nil {
+		return nil, ctx.Err
+	}
+	if str != "" {
+		fmt.Fprint(ctx.Stdout, str+" ")
+	}
+
+	var response string
+	if _, err := fmt.Scan(&response); err != nil {
+		return nil, err
+	}
+
+	update := map[string]interface{}{"response": response}
+
+	switch v := ctx.Lookup("response"); v.IncompleteKind() {
+	case cue.BoolKind:
+		switch strings.ToLower(response) {
+		case "yes":
+			update["response"] = true
+		default:
+			update["response"] = false
+		}
+	case cue.StringKind:
+		// already set above
+	}
+	return update, nil
+}
diff --git a/pkg/tool/cli/doc.go b/pkg/tool/cli/doc.go
index e65ebcf..c63be7e 100644
--- a/pkg/tool/cli/doc.go
+++ b/pkg/tool/cli/doc.go
@@ -12,7 +12,6 @@
 //     	text: string
 //     }
 //
-//     // TODO:
 //     // Ask prompts the current console with a message and waits for input.
 //     //
 //     // Example:
@@ -20,15 +19,15 @@
 //     //         prompt:   "Are you okay?"
 //     //         repsonse: bool
 //     //     })
-//     // Ask: {
-//     //  kind: "tool/cli.Ask"
+//     Ask: {
+//     	kind: "tool/cli.Ask"
 //
-//     //  // prompt sends this message to the output.
-//     //  prompt: string
+//     	// prompt sends this message to the output.
+//     	prompt: string
 //
-//     //  // response holds the user's response. If it is a boolean expression it
-//     //  // will interpret the answer using textual yes/ no.
-//     //  response: string | bool
-//     // }
+//     	// response holds the user's response. If it is a boolean expression it
+//     	// will interpret the answer using textual yes/ no.
+//     	response: string | bool
+//     }
 //
 package cli
diff --git a/pkg/tool/cli/pkg.go b/pkg/tool/cli/pkg.go
index 1cd3d33..0a9e50f 100644
--- a/pkg/tool/cli/pkg.go
+++ b/pkg/tool/cli/pkg.go
@@ -23,5 +23,10 @@
 		$id:  *"tool/cli.Print" | "print"
 		text: string
 	}
+	Ask: {
+		kind:     "tool/cli.Ask"
+		prompt:   string
+		response: string | bool
+	}
 }`,
 }