cue: clean up Format

Makes format more intuitive and gives bonus features
to mitigate any pain this causes for backwards
incompatibility.

Fixes #882

Change-Id: I6390f95c4e7b27b9e0a195bd936f6aae55aadf27
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9487
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/mod.go b/cmd/cue/cmd/mod.go
index ff95eb1..833ad0f 100644
--- a/cmd/cue/cmd/mod.go
+++ b/cmd/cue/cmd/mod.go
@@ -90,7 +90,7 @@
 			return fmt.Errorf("invalid module name: %v", module)
 		}
 		if h := u.Hostname(); !strings.Contains(h, ".") {
-			return fmt.Errorf("invalid host name %q", h)
+			return fmt.Errorf("invalid host name %s", h)
 		}
 	}
 
diff --git a/cue/builtin_test.go b/cue/builtin_test.go
index 20d92c8..e8b72d5 100644
--- a/cue/builtin_test.go
+++ b/cue/builtin_test.go
@@ -47,13 +47,13 @@
 		`3`,
 	}, {
 		test("math", "math.Pi(3)"),
-		`_|_(cannot call non-function math.Pi (type float))`,
+		`_|_ // cannot call non-function math.Pi (type float)`,
 	}, {
 		test("math", "math.Floor(3, 5)"),
-		`_|_(too many arguments in call to math.Floor (have 2, want 1))`,
+		`_|_ // too many arguments in call to math.Floor (have 2, want 1)`,
 	}, {
 		test("math", `math.Floor("foo")`),
-		`_|_(cannot use "foo" (type string) as number in argument 1 to math.Floor)`,
+		`_|_ // cannot use "foo" (type string) as number in argument 1 to math.Floor`,
 	}, {
 		test("crypto/sha256", `sha256.Sum256("hash me")`),
 		`'\xeb \x1a\xf5\xaa\xf0\xd6\x06)\xd3Ҧ\x1eFl\xfc\x0f\xed\xb5\x17\xad\xd81\xec\xacR5\xe1کc\xd6'`,
@@ -62,13 +62,13 @@
 		`16`,
 	}, {
 		test("encoding/yaml", `yaml.Validate("a: 2\n---\na: 4", {a:<3})`),
-		`_|_(error in call to encoding/yaml.Validate: a: invalid value 4 (out of bound <3))`,
+		`_|_ // error in call to encoding/yaml.Validate: a: invalid value 4 (out of bound <3)`,
 	}, {
 		test("encoding/yaml", `yaml.Validate("a: 2\n---\na: 4", {a:<5})`),
 		`true`,
 	}, {
 		test("encoding/yaml", `yaml.Validate("a: 2\n", {a:<5, b:int})`),
-		`_|_(error in call to encoding/yaml.Validate: b: incomplete value int)`,
+		`_|_ // error in call to encoding/yaml.Validate: b: incomplete value int`,
 	}, {
 		test("strconv", `strconv.FormatUint(64, 16)`),
 		`"40"`,
@@ -77,7 +77,7 @@
 		`"foo"`,
 	}, {
 		test("regexp", `regexp.Find(#"f\w\w"#, "bar")`),
-		`_|_(error in call to regexp.Find: no match)`,
+		`_|_ // error in call to regexp.Find: no match`,
 	}, {
 		testExpr(`len([1, 2, 3])`),
 		`3`,
@@ -86,33 +86,38 @@
 		`3`,
 	}, {
 		test("encoding/json", `json.MarshalStream([{a: 1}, {b: 2}])`),
-		`"{\"a\":1}\n{\"b\":2}\n"`,
+		`"""` + "\n\t{\"a\":1}\n\t{\"b\":2}\n\t\n\t" + `"""`,
 	}, {
 		test("encoding/json", `{
 			x: int
 			y: json.Marshal({a: x})
 		}`),
-		`{x:int,y:_|_(cannot convert incomplete value "int" to JSON)}`,
+		`{
+	x: int
+	y: _|_ // cannot convert incomplete value "int" to JSON
+}`,
 	}, {
 		test("encoding/yaml", `yaml.MarshalStream([{a: 1}, {b: 2}])`),
-		`"a: 1\n---\nb: 2\n"`,
+		`"""` + "\n\ta: 1\n\t---\n\tb: 2\n\t\n\t" + `"""`,
 	}, {
 		test("struct", `struct.MinFields(0) & ""`),
-		`_|_(conflicting values struct.MinFields(0) and "" (mismatched types struct and string))`,
+		`_|_ // conflicting values struct.MinFields(0) and "" (mismatched types struct and string)`,
 	}, {
 		test("struct", `struct.MinFields(0) & {a: 1}`),
-		`{a:1}`,
+		`{
+	a: 1
+}`,
 	}, {
 		test("struct", `struct.MinFields(2) & {a: 1}`),
 		// TODO: original value may be better.
-		// `_|_(invalid value {a:1} (does not satisfy struct.MinFields(2)))`,
-		`_|_(invalid value {a:1} (does not satisfy struct.MinFields(2)): len(fields) < MinFields(2) (1 < 2))`,
+		// `_|_ // invalid value {a:1} (does not satisfy struct.MinFields(2))`,
+		`_|_ // invalid value {a:1} (does not satisfy struct.MinFields(2)): len(fields) < MinFields(2) (1 < 2)`,
 	}, {
 		test("time", `time.Time & "1937-01-01T12:00:27.87+00:20"`),
 		`"1937-01-01T12:00:27.87+00:20"`,
 	}, {
 		test("time", `time.Time & "no time"`),
-		`_|_(invalid value "no time" (does not satisfy time.Time): error in call to time.Time: invalid time "no time")`,
+		`_|_ // invalid value "no time" (does not satisfy time.Time): error in call to time.Time: invalid time "no time"`,
 	}, {
 		test("time", `time.Unix(1500000000, 123456)`),
 		`"2017-07-14T02:40:00.000123456Z"`,
@@ -146,7 +151,7 @@
 		emit      string
 	}{{
 		test("list", `list.Sort([{a:1}, {b:2}], list.Ascending)`),
-		`_|_(error in call to list.Sort: less: invalid operands {b:2} and {a:1} to '<' (type struct and struct))`,
+		`_|_ // error in call to list.Sort: less: invalid operands {b:2} and {a:1} to '<' (type struct and struct)`,
 	}}
 	for i, tc := range testCases {
 		t.Run(fmt.Sprint(i), func(t *testing.T) {
diff --git a/cue/examplecompile_test.go b/cue/examplecompile_test.go
index 6803da3..0172235 100644
--- a/cue/examplecompile_test.go
+++ b/cue/examplecompile_test.go
@@ -31,13 +31,13 @@
 	`)
 
 	p("lookups")
-	p("a:     %+v", v.LookupPath(cue.ParsePath("a")))
-	p("b:     %+v", v.LookupPath(cue.ParsePath("b")))
-	p(`"a+b": %+v`, v.LookupPath(cue.ParsePath(`"a+b"`)))
+	p("a:     %v", v.LookupPath(cue.ParsePath("a")))
+	p("b:     %v", v.LookupPath(cue.ParsePath("b")))
+	p(`"a+b": %v`, v.LookupPath(cue.ParsePath(`"a+b"`)))
 	p("")
 	p("expressions")
-	p("a + b: %+v", ctx.CompileString("a + b", cue.Scope(v)))
-	p("a * b: %+v", ctx.CompileString("a * b", cue.Scope(v)))
+	p("a + b: %v", ctx.CompileString("a + b", cue.Scope(v)))
+	p("a * b: %v", ctx.CompileString("a * b", cue.Scope(v)))
 
 	// Output:
 	// lookups
diff --git a/cue/format.go b/cue/format.go
new file mode 100644
index 0000000..707a799
--- /dev/null
+++ b/cue/format.go
@@ -0,0 +1,201 @@
+// Copyright 2021 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cue
+
+import (
+	"bytes"
+	"fmt"
+	"math/big"
+
+	"cuelang.org/go/cue/ast"
+	"cuelang.org/go/cue/format"
+	"cuelang.org/go/internal/core/export"
+)
+
+// TODO:
+// * allow '-' to strip outer curly braces?
+//     -    simplify output; can be used in combination with other flags
+// * advertise:
+//     c    like v, but print comments
+//     a    like c, but print attributes and package-local hidden fields as well
+
+// Format prints a CUE value.
+//
+// WARNING:
+//     although we are narrowing down the semantics, the verbs and options
+//     are still subject to change. this API is experimental although it is
+//     likely getting close to the final design.
+//
+// It recognizes the following verbs:
+//
+//     v    print CUE value
+//
+// The verbs support the following flags:
+//     #    print as schema and include definitions.
+//          The result is printed as a self-contained file, instead of an the
+//          expression format.
+//     +    evaluate: resolve defaults and error on incomplete errors
+//
+// Indentation can be controlled as follows:
+//     width      indent the cue block by <width> tab stops (e.g. %2v)
+//     precision  convert tabs to <precision> spaces (e.g. %.2v), where
+//                a value of 0 means no indentation or newlines (TODO).
+//
+// If the value kind corresponds to one of the following Go types, the
+// usual Go formatting verbs for that type can be used:
+//
+//     Int:          b,d,o,O,q,x,X
+//     Float:        f,e,E,g,G
+//     String/Bytes: s,q,x,X
+//
+// The %v directive will be used if the type is not supported for that verb.
+//
+func (v Value) Format(state fmt.State, verb rune) {
+	if v.v == nil {
+		fmt.Fprint(state, "<nil>")
+		return
+	}
+
+	switch verb {
+	case 'a':
+		formatCUE(state, v, true, true)
+	case 'c':
+		formatCUE(state, v, true, false)
+	case 'v':
+		formatCUE(state, v, false, false)
+
+	case 'd', 'o', 'O', 'U':
+		var i big.Int
+		if _, err := v.Int(&i); err != nil {
+			formatCUE(state, v, false, false)
+			return
+		}
+		i.Format(state, verb)
+
+	case 'f', 'e', 'E', 'g', 'G':
+		d, err := v.Decimal()
+		if err != nil {
+			formatCUE(state, v, false, false)
+			return
+		}
+		d.Format(state, verb)
+
+	case 's', 'q':
+		// TODO: this drops other formatting directives
+		msg := "%s"
+		if verb == 'q' {
+			msg = "%q"
+		}
+
+		if b, err := v.Bytes(); err == nil {
+			fmt.Fprintf(state, msg, b)
+		} else {
+			s := fmt.Sprintf("%+v", v)
+			fmt.Fprintf(state, msg, s)
+		}
+
+	case 'x', 'X':
+		switch v.Kind() {
+		case StringKind, BytesKind:
+			b, _ := v.Bytes()
+			// TODO: this drops other formatting directives
+			msg := "%x"
+			if verb == 'X' {
+				msg = "%X"
+			}
+			fmt.Fprintf(state, msg, b)
+
+		case IntKind, NumberKind:
+			var i big.Int
+			_, _ = v.Int(&i)
+			i.Format(state, verb)
+
+		case FloatKind:
+			dec, _ := v.Decimal()
+			dec.Format(state, verb)
+
+		default:
+			formatCUE(state, v, false, false)
+		}
+
+	default:
+		formatCUE(state, v, false, false)
+	}
+}
+
+func formatCUE(state fmt.State, v Value, showDocs, showAll bool) {
+
+	pkgPath := v.instance().ID()
+
+	p := *export.Simplified
+
+	isDef := false
+	switch {
+	case state.Flag('#'):
+		isDef = true
+		p = export.Profile{
+			ShowOptional:    true,
+			ShowDefinitions: true,
+			ShowHidden:      true,
+		}
+
+	case state.Flag('+'):
+		p = *export.Final
+		fallthrough
+
+	default:
+		p.ShowHidden = showAll
+	}
+
+	p.ShowDocs = showDocs
+	p.ShowAttributes = showAll
+
+	var n ast.Node
+	if isDef {
+		n, _ = p.Def(v.idx, pkgPath, v.v)
+	} else {
+		n, _ = p.Value(v.idx, pkgPath, v.v)
+	}
+
+	formatExpr(state, n)
+}
+
+func formatExpr(state fmt.State, n ast.Node) {
+	opts := make([]format.Option, 0, 3)
+	if state.Flag('-') {
+		opts = append(opts, format.Simplify())
+	}
+	// TODO: handle verbs to allow formatting based on type:
+	if width, ok := state.Width(); ok {
+		opts = append(opts, format.IndentPrefix(width))
+	}
+	// TODO: consider this: should tabs or spaces be the default?
+	if tabwidth, ok := state.Precision(); ok {
+		// TODO: 0 means no newlines.
+		opts = append(opts,
+			format.UseSpaces(tabwidth),
+			format.TabIndent(false))
+	}
+	// TODO: consider this.
+	//  else if state.Flag(' ') {
+	// 	opts = append(opts,
+	// 		format.UseSpaces(4),
+	// 		format.TabIndent(false))
+	// }
+
+	b, _ := format.Node(n, opts...)
+	b = bytes.Trim(b, "\n\r")
+	_, _ = state.Write(b)
+}
diff --git a/cue/format_test.go b/cue/format_test.go
new file mode 100644
index 0000000..8b02725
--- /dev/null
+++ b/cue/format_test.go
@@ -0,0 +1,307 @@
+// Copyright 2021 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cue_test
+
+import (
+	"fmt"
+	"path"
+	"testing"
+
+	"cuelang.org/go/cue"
+	"cuelang.org/go/cue/cuecontext"
+)
+
+func ExampleValue_Format() {
+	ctx := cuecontext.New()
+
+	v := ctx.CompileString(`
+		a: 2 + b
+		b: *3 | int
+		s: "foo\nbar"
+	`)
+
+	fmt.Println("### ALL")
+	fmt.Println(v)
+	fmt.Println("---")
+	fmt.Printf("%#v\n", v)
+	fmt.Println("---")
+	fmt.Printf("%+v\n", v)
+
+	a := v.LookupPath(cue.ParsePath("a"))
+	fmt.Println("\n### INT")
+	fmt.Printf("%%v:   %v\n", a)
+	fmt.Printf("%%05d: %05d\n", a)
+
+	s := v.LookupPath(cue.ParsePath("s"))
+	fmt.Println("\n### STRING")
+	fmt.Printf("%%v: %v\n", s)
+	fmt.Printf("%%s: %s\n", s)
+	fmt.Printf("%%q: %q\n", s)
+
+	v = ctx.CompileString(`
+		#Def: a: [string]: int
+		b: #Def
+		b: a: {
+			a: 3
+			b: 3
+		}
+	`)
+	b := v.LookupPath(cue.ParsePath("b.a"))
+	fmt.Println("\n### DEF")
+	fmt.Println(b)
+	fmt.Println("---")
+	// This will indicate that the result is closed by including a hidden
+	// definition.
+	fmt.Printf("%#v\n", b)
+
+	// Output:
+	// ### ALL
+	// {
+	// 	a: 5
+	// 	b: *3 | int
+	// 	s: """
+	// 		foo
+	// 		bar
+	// 		"""
+	// }
+	// ---
+	// a: 2 + b
+	// b: *3 | int
+	// s: "foo\nbar"
+	// ---
+	// {
+	// 	a: 5
+	// 	b: 3
+	// 	s: """
+	// 		foo
+	// 		bar
+	// 		"""
+	// }
+	//
+	// ### INT
+	// %v:   5
+	// %05d: 00005
+	//
+	// ### STRING
+	// %v: """
+	// 	foo
+	// 	bar
+	// 	"""
+	// %s: foo
+	// bar
+	// %q: "foo\nbar"
+	//
+	// ### DEF
+	// {
+	// 	a: 3
+	// 	b: 3
+	// }
+	// ---
+	// _#def
+	// _#def: {
+	// 	{
+	// 		[string]: int
+	// 	}
+	// 	a: 3
+	// 	b: 3
+	// }
+}
+
+func TestFormat(t *testing.T) {
+	tests := func(s ...string) (a [][2]string) {
+		for i := 0; i < len(s); i += 2 {
+			a = append(a, [2]string{s[i], s[i+1]})
+		}
+		return a
+	}
+	testCases := []struct {
+		desc string
+		in   string
+		out  [][2]string
+	}{{
+		desc: "int",
+		in:   `12 + 14`,
+		out: tests(
+			"%#v", "26",
+			"%d", "26",
+			"%o", "32",
+			"%O", "0o32",
+			"%x", "1a",
+			"%X", "1A",
+			"%q", `"26"`,
+			"%0.3d", "026",
+		),
+	}, {
+		desc: "float",
+		in:   `12.2 + 14.4`,
+		out: tests(
+			"%#v", "26.6",
+			"%5f", " 26.6",
+			"%e", "2.66e+1",
+			"%08E", "02.66E+1",
+			"%g", "26.6",
+			"%3G", "26.6",
+		),
+	}, {
+		desc: "strings",
+		in:   `"string"`,
+		out: tests(
+			"%v", `"string"`,
+			"%s", "string",
+			"%x", "737472696e67",
+			"%X", "737472696E67",
+		),
+	}, {
+		desc: "multiline string",
+		in: `"""
+		foo
+		bar
+		"""`,
+		out: tests(
+			"%#v", `"""
+	foo
+	bar
+	"""`,
+			"%s", "foo\nbar",
+			"%q", `"foo\nbar"`,
+		),
+	}, {
+		desc: "multiline bytes",
+		in: `'''
+			foo
+			bar
+			'''`,
+		out: tests(
+			"%#v", `'''
+	foo
+	bar
+	'''`,
+			"%s", "foo\nbar",
+			"%q", `"foo\nbar"`,
+		),
+	}, {
+		desc: "interpolation",
+		in: `
+		#D: {
+			a: string
+			b: "hello \(a)"
+		}
+		d: #D
+		d: a: "world"
+		x: *1 | int
+		`,
+		out: tests(
+			"%v", `{
+	d: {
+		a: "world"
+		b: "hello world"
+	}
+	x: *1 | int
+}`,
+			"%#v", `#D: {
+	a: string
+	b: "hello \(a)"
+}
+d: #D & {
+	a: "world"
+}
+x: *1 | int`,
+			"%+v", `{
+	d: {
+		a: "world"
+		b: "hello world"
+	}
+	x: 1
+}`,
+		),
+	}, {
+		desc: "indent",
+		in: `
+a: {
+	b: """
+		foo
+		bar
+		"""
+	c: int
+}`,
+		out: tests(
+			"%v", `{
+	a: {
+		b: """
+			foo
+			bar
+			"""
+		c: int
+	}
+}`,
+			"%3v", `{
+				a: {
+					b: """
+						foo
+						bar
+						"""
+					c: int
+				}
+			}`,
+			"%.1v", `{
+ a: {
+  b: """
+   foo
+   bar
+   """
+  c: int
+ }
+}`,
+			"%3.1v", `{
+    a: {
+     b: """
+      foo
+      bar
+      """
+     c: int
+    }
+   }`,
+		),
+	}, {
+		desc: "imports",
+		in: `
+		import "strings"
+		a: strings.Contains("foo")
+		`,
+		out: tests(
+			"%v", `{
+	a: strings.Contains("foo")
+}`,
+			"%+v", `{
+	a: strings.Contains("foo")
+}`,
+			"%#v", `import "strings"
+
+a: strings.Contains("foo")`,
+		),
+	}}
+	ctx := cuecontext.New()
+	for _, tc := range testCases {
+		for _, test := range tc.out {
+			t.Run(path.Join(tc.desc, test[0]), func(t *testing.T) {
+				v := ctx.CompileString(tc.in)
+				got := fmt.Sprintf(test[0], v)
+				if got != test[1] {
+					t.Errorf(" got: %s\nwant: %s", got, test[1])
+				}
+			})
+		}
+	}
+}
diff --git a/cue/marshal_test.go b/cue/marshal_test.go
index 64775aa..502dcc0 100644
--- a/cue/marshal_test.go
+++ b/cue/marshal_test.go
@@ -148,9 +148,9 @@
 				`package test
 
 		import pkg2 "example.com/foo/pkg1"
-		pkg1: pkg2.Object
+		"Hello \(pkg1)!"
 
-		"Hello \(pkg1)!"`),
+		pkg1: pkg2.Object`),
 		}),
 		`"Hello World!"`,
 	}, {
diff --git a/cue/types.go b/cue/types.go
index 2629a8a..6421c0a 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -29,7 +29,6 @@
 	"cuelang.org/go/cue/ast"
 	"cuelang.org/go/cue/ast/astutil"
 	"cuelang.org/go/cue/errors"
-	"cuelang.org/go/cue/format"
 	"cuelang.org/go/cue/literal"
 	"cuelang.org/go/cue/token"
 	"cuelang.org/go/internal"
@@ -1828,25 +1827,6 @@
 	return adt.Equal(v.ctx(), v.v, other.v, 0)
 }
 
-// Format prints a debug version of a value.
-func (v Value) Format(state fmt.State, verb rune) {
-	ctx := v.ctx()
-	if v.v == nil {
-		fmt.Fprint(state, "<nil>")
-		return
-	}
-	switch {
-	case state.Flag('#'):
-		_, _ = io.WriteString(state, str(ctx, v.v))
-	case state.Flag('+'):
-		_, _ = io.WriteString(state, ctx.Str(v.v))
-	default:
-		n, _ := export.Raw.Expr(v.idx, v.instance().ID(), v.v)
-		b, _ := format.Node(n)
-		_, _ = state.Write(b)
-	}
-}
-
 func (v Value) instance() *Instance {
 	if v.v == nil {
 		return nil
diff --git a/cue/types_test.go b/cue/types_test.go
index 18d52ae..fff8dfe 100644
--- a/cue/types_test.go
+++ b/cue/types_test.go
@@ -63,7 +63,7 @@
 			res := runSpec.Unify(v)
 			return res
 		},
-		want: "_|_(#runSpec: field ction not allowed)",
+		want: "_|_ // #runSpec: field ction not allowed",
 	}, {
 		// Issue #567
 		input: `
@@ -77,7 +77,7 @@
 			res := runSpec.Unify(v)
 			return res
 		},
-		want: "_|_(#runSpec.action: field Foo not allowed)",
+		want: "_|_ // #runSpec.action: field Foo not allowed",
 	}, {
 		input: `
 		#runSpec: v: {action: foo: int}
@@ -91,7 +91,7 @@
 			res := w.Unify(v)
 			return res
 		},
-		want: "_|_(w: field ction not allowed)",
+		want: "_|_ // w: field ction not allowed",
 	}}
 	for _, tc := range testCases {
 		if tc.skip {
@@ -819,7 +819,7 @@
 	for _, tc := range testCases {
 		v := inst.Lookup(tc.ref...)
 
-		if got := fmt.Sprint(v); got != tc.raw {
+		if got := fmt.Sprintf("%#v", v); got != tc.raw {
 			t.Errorf("got %v; want %v", got, tc.raw)
 		}
 
@@ -841,7 +841,7 @@
 			v = fi.Value
 		}
 
-		if got := fmt.Sprint(v); got != tc.raw {
+		if got := fmt.Sprintf("%#v", v); got != tc.raw {
 			t.Errorf("got %v; want %v", got, tc.raw)
 		}
 
@@ -956,22 +956,20 @@
 		t.Fatal(err)
 	}
 
-	got := fmt.Sprint(root.Value())
-	want := `{
-	#Provider: {
-		ID:          string
+	got := fmt.Sprintf("%#v", root.Value())
+	want := `#Provider: {
+	ID:          string
+	notConcrete: bool
+	a:           int
+	b:           int
+}
+providers: {
+	myprovider: {
+		ID:          "12345"
 		notConcrete: bool
 		a:           int
 		b:           int
 	}
-	providers: {
-		myprovider: {
-			ID:          "12345"
-			notConcrete: bool
-			a:           int
-			b:           int
-		}
-	}
 }`
 	if got != want {
 		t.Errorf("got:  %s\nwant: %s", got, want)
diff --git a/encoding/openapi/types.go b/encoding/openapi/types.go
index 50a962e..64b2753 100644
--- a/encoding/openapi/types.go
+++ b/encoding/openapi/types.go
@@ -63,7 +63,7 @@
 	if op == cue.CallOp {
 		v = a[0]
 		if len(a) == 2 {
-			arg = fmt.Sprintf(" (%s)", a[1].Eval())
+			arg = fmt.Sprintf(" (%v)", a[1].Eval())
 		}
 	}
 	if inst, ref := v.Reference(); len(ref) > 0 {
diff --git a/internal/diff/diff_test.go b/internal/diff/diff_test.go
index 1bfec73..1eb31a3 100644
--- a/internal/diff/diff_test.go
+++ b/internal/diff/diff_test.go
@@ -114,7 +114,7 @@
 		`,
 		kind: Modified,
 		diff: `  {
-      ls: [2,3,4]
+      ls: [2, 3, 4]
 -     "foo-bar": 2
 +     "foo-bar": 3
       s: 4
@@ -128,7 +128,7 @@
       lm2: [
 -         6,
       ]
-+     la: [2,3,4]
++     la: [2, 3, 4]
   }
 `,
 	}, {
@@ -302,7 +302,9 @@
 		`,
 		kind: Modified,
 		diff: `  {
--     a: {x:"hello"}
+-     a: {
+-     	x: "hello"
+-     }
   }
 `,
 	}, {
diff --git a/pkg/net/host.go b/pkg/net/host.go
index 6018da4..5f2f2e3 100644
--- a/pkg/net/host.go
+++ b/pkg/net/host.go
@@ -57,7 +57,7 @@
 	case cue.ListKind:
 		ipdata := netGetIP(host)
 		if len(ipdata) != 4 && len(ipdata) != 16 {
-			err = fmt.Errorf("invalid host %q", host)
+			err = fmt.Errorf("invalid host %s", host)
 		}
 		hostStr = ipdata.String()
 	case cue.BytesKind: