doc/tutorial/kubernetes: update tool examples

Change-Id: I1e6a1398063a6508525fd666cd93a8c38aa28cbe
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/1941
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cue/builtins.go b/cue/builtins.go
index f815b8e..e435b18 100644
--- a/cue/builtins.go
+++ b/cue/builtins.go
@@ -1807,14 +1807,36 @@
 				c.ret, c.err = func() (interface{}, error) {
 					buf := &bytes.Buffer{}
 					tw := tabwriter.NewWriter(buf, 0, 4, 1, ' ', 0)
-					b, err := data.Bytes()
-					if err != nil {
-						return "", err
+
+					write := func(v Value) error {
+						b, err := v.Bytes()
+						if err != nil {
+							return err
+						}
+						_, err = tw.Write(b)
+						if err != nil {
+							return err
+						}
+						return nil
 					}
-					_, err = tw.Write(b)
-					if err != nil {
-						return "", err
+
+					switch data.Kind() {
+					case BytesKind, StringKind:
+						if err := write(data); err != nil {
+							return "", err
+						}
+					case ListKind:
+						for i, _ := data.List(); i.Next(); {
+							if err := write(i.Value()); err != nil {
+								return "", err
+							}
+							tw.Write([]byte{'\n'})
+						}
+					default:
+						return "", fmt.Errorf("tabwriter.Write: unsupported type %v", data.Kind())
 					}
+
+					err := tw.Flush()
 					return buf.String(), err
 				}()
 			},
diff --git a/doc/tutorial/kubernetes/quick/services/create_tool.cue b/doc/tutorial/kubernetes/quick/services/create_tool.cue
index 1713fa5..573890e 100644
--- a/doc/tutorial/kubernetes/quick/services/create_tool.cue
+++ b/doc/tutorial/kubernetes/quick/services/create_tool.cue
@@ -1,16 +1,19 @@
 package kube
 
-import "encoding/yaml"
+import (
+	"encoding/yaml"
+	"tool/exec"
+	"tool/cli"
+)
 
 command create: {
-    task kube: {
-        kind:   "exec"
-        cmd:    "kubectl create --dry-run -f -"
-        stdin:  yaml.MarshalStream(objects)
-        stdout: string
-    }
-    task display: {
-        kind: "print"
-        text: task.kube.stdout
-    }
+	task kube: exec.Run & {
+		cmd:    "kubectl create --dry-run -f -"
+		stdin:  yaml.MarshalStream(objects)
+		stdout: string
+	}
+
+	task display: cli.Print & {
+		text: task.kube.stdout
+	}
 }
diff --git a/doc/tutorial/kubernetes/quick/services/dump_tool.cue b/doc/tutorial/kubernetes/quick/services/dump_tool.cue
index dd19dc6..5567771 100644
--- a/doc/tutorial/kubernetes/quick/services/dump_tool.cue
+++ b/doc/tutorial/kubernetes/quick/services/dump_tool.cue
@@ -1,10 +1,12 @@
 package kube
 
-import "encoding/yaml"
+import (
+	"encoding/yaml"
+	"tool/cli"
+)
 
 command dump: {
-    task print: {
-        kind: "print"
-        text: yaml.MarshalStream(objects)
-    }
+	task print: cli.Print & {
+		text: yaml.MarshalStream(objects)
+	}
 }
diff --git a/doc/tutorial/kubernetes/quick/services/ls_tool.cue b/doc/tutorial/kubernetes/quick/services/ls_tool.cue
index 0bd4499..b0d4718 100644
--- a/doc/tutorial/kubernetes/quick/services/ls_tool.cue
+++ b/doc/tutorial/kubernetes/quick/services/ls_tool.cue
@@ -1,13 +1,21 @@
 package kube
 
-import "strings"
+import (
+	"text/tabwriter"
+	"tool/cli"
+	"tool/file"
+)
 
 command ls: {
-    task print: {
-        kind: "print"
-        Lines = [
-            "\(x.kind)  \t\(x.metadata.labels.component)   \t\(x.metadata.name)"
-            for x in objects ]
-        text: strings.Join(Lines, "\n")
-    }
+	task print: cli.Print & {
+		text: tabwriter.Write([
+			"\(x.kind)  \t\(x.metadata.labels.component)  \t\(x.metadata.name)"
+			for x in objects
+		])
+	}
+
+	task write: file.Create & {
+		filename: "foo.txt"
+		contents: task.print.text
+	}
 }
diff --git a/pkg/text/tabwriter/manual.go b/pkg/text/tabwriter/manual.go
index b031a5b..4c65af5 100644
--- a/pkg/text/tabwriter/manual.go
+++ b/pkg/text/tabwriter/manual.go
@@ -16,6 +16,7 @@
 
 import (
 	"bytes"
+	"fmt"
 	"text/tabwriter"
 
 	"cuelang.org/go/cue"
@@ -26,13 +27,35 @@
 func Write(data cue.Value) (string, error) {
 	buf := &bytes.Buffer{}
 	tw := tabwriter.NewWriter(buf, 0, 4, 1, ' ', 0)
-	b, err := data.Bytes()
-	if err != nil {
-		return "", err
+
+	write := func(v cue.Value) error {
+		b, err := v.Bytes()
+		if err != nil {
+			return err
+		}
+		_, err = tw.Write(b)
+		if err != nil {
+			return err
+		}
+		return nil
 	}
-	_, err = tw.Write(b)
-	if err != nil {
-		return "", err
+
+	switch data.Kind() {
+	case cue.BytesKind, cue.StringKind:
+		if err := write(data); err != nil {
+			return "", err
+		}
+	case cue.ListKind:
+		for i, _ := data.List(); i.Next(); {
+			if err := write(i.Value()); err != nil {
+				return "", err
+			}
+			tw.Write([]byte{'\n'})
+		}
+	default:
+		return "", fmt.Errorf("tabwriter.Write: unsupported type %v", data.Kind())
 	}
+
+	err := tw.Flush()
 	return buf.String(), err
 }