cue/errors: print positions explicitly

This gives more control over printing and
prepares for error rework.

Issue #52

Change-Id: I5629109298341cc700f860a6610f9362b7741a22
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2168
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cmd/cue/cmd/testdata/tasks/cmd_baddisplay.out b/cmd/cue/cmd/testdata/tasks/cmd_baddisplay.out
index c691b70..753329f 100644
--- a/cmd/cue/cmd/testdata/tasks/cmd_baddisplay.out
+++ b/cmd/cue/cmd/testdata/tasks/cmd_baddisplay.out
@@ -1,4 +1,3 @@
 unsupported op &(int, string):
     $CWD/testdata/tasks/task_tool.cue:29:9
     tool/cli:4:9
-    
diff --git a/cue/errors.go b/cue/errors.go
index 62aa4e7..5ffa449 100644
--- a/cue/errors.go
+++ b/cue/errors.go
@@ -81,7 +81,7 @@
 
 func (x *bottom) kind() kind { return bottomKind }
 
-func (x *bottom) Position() []token.Pos {
+func (x *bottom) Positions() []token.Pos {
 	if x.index != nil {
 		return appendPositions(nil, x.pos)
 	}
diff --git a/cue/errors/errors.go b/cue/errors/errors.go
index 61e4dab..949da11 100644
--- a/cue/errors/errors.go
+++ b/cue/errors/errors.go
@@ -22,6 +22,7 @@
 	"cuelang.org/go/cue/token"
 	"golang.org/x/exp/errors"
 	"golang.org/x/exp/errors/fmt"
+	"golang.org/x/xerrors"
 )
 
 // New is a convenience wrapper for errors.New in the core library.
@@ -115,14 +116,14 @@
 	return &posError{err: err}
 }
 
-func (e posError) Position() token.Position {
+func (e *posError) Position() token.Position {
 	return e.pos
 }
 
 // Error implements the error interface.
-func (e posError) Error() string { return fmt.Sprint(e) }
+func (e *posError) Error() string { return fmt.Sprint(e) }
 
-func (e posError) FormatError(p errors.Printer) error {
+func (e *posError) FormatError(p errors.Printer) error {
 	next := e.err
 	if e.msg == "" {
 		next = errFormat(p, e.err)
@@ -136,6 +137,10 @@
 
 }
 
+func (e posError) Unwrap() error {
+	return e.err
+}
+
 func errFormat(p errors.Printer, err error) (next error) {
 	switch v := err.(type) {
 	case errors.Formatter:
@@ -250,6 +255,30 @@
 	}
 }
 
-func printError(w io.Writer, err Error) {
-	fmt.Fprintf(w, "%+v\n", err)
+func printError(w io.Writer, err error) {
+	fmt.Fprintf(w, "%v", err)
+	printedColon := false
+	for ; err != nil; err = xerrors.Unwrap(err) {
+		switch x := err.(type) {
+		case interface{ Position() token.Position }:
+			if pos := x.Position().String(); pos != "-" {
+				if !printedColon {
+					fmt.Fprint(w, ":")
+					printedColon = true
+				}
+				fmt.Fprintf(w, "\n    %v", pos)
+			}
+		case interface{ Positions() []token.Pos }:
+			for _, p := range x.Positions() {
+				if p.IsValid() {
+					if !printedColon {
+						fmt.Fprint(w, ":")
+						printedColon = true
+					}
+					fmt.Fprintf(w, "\n    %v", p)
+				}
+			}
+		}
+	}
+	fmt.Fprintln(w)
 }