errors/fmt: avoid printing spurious colon

This happened when Detail is called but nothing
is printed.

Also gobble a newline at the start of printing detail.
Gobbling a newline at either the start or end simplifies
implementations, such as printing a list of stack traces.

Change-Id: I01af5c219745104600d01f9b543a054e7c1385f1
Reviewed-on: https://go-review.googlesource.com/c/152998
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/errors/fmt/errors.go b/errors/fmt/errors.go
index 4bc00b3..3150cc5 100644
--- a/errors/fmt/errors.go
+++ b/errors/fmt/errors.go
@@ -201,7 +201,18 @@
 func (p *errPPState) Write(b []byte) (n int, err error) {
 	if !p.fmt.inDetail || p.fmt.plusV {
 		k := 0
+		if len(b) == 0 {
+			return 0, nil
+		}
 		if p.fmt.indent {
+			if p.fmt.needNewline {
+				p.fmt.needNewline = false
+				p.buf.WriteByte(':')
+				p.buf.Write(detailSep)
+				if b[0] == '\n' {
+					b = b[1:]
+				}
+			}
 			for i, c := range b {
 				if c == '\n' {
 					p.buf.Write(b[k:i])
@@ -243,7 +254,7 @@
 	p.fmt.inDetail = true
 	p.fmt.indent = p.fmt.plusV
 	if p.fmt.plusV && !inDetail {
-		(*errPPState)(p).Write([]byte(":\n"))
+		p.fmt.needNewline = true
 	}
 	return p.fmt.plusV
 }
diff --git a/errors/fmt/errors_test.go b/errors/fmt/errors_test.go
index 4757ac8..6a0ce27 100644
--- a/errors/fmt/errors_test.go
+++ b/errors/fmt/errors_test.go
@@ -232,6 +232,23 @@
 			"\nnewline: and another" +
 			"\none",
 	}, {
+		err:  spurious(""),
+		fmt:  "%s",
+		want: "spurious",
+	}, {
+		err:  spurious(""),
+		fmt:  "%+v",
+		want: "spurious",
+	}, {
+		err:  spurious("extra"),
+		fmt:  "%s",
+		want: "spurious",
+	}, {
+		err: spurious("extra"),
+		fmt: "%+v",
+		want: "spurious:\n" +
+			"    extra",
+	}, {
 		err:  nil,
 		fmt:  "%+v",
 		want: "<nil>",
@@ -344,6 +361,21 @@
 	return nil
 }
 
+type spurious string
+
+func (e spurious) Error() string { return fmt.Sprint(e) }
+
+func (e spurious) Format(p errors.Printer) (next error) {
+	p.Print("spurious")
+	p.Detail() // Call detail even if we don't print anything
+	if e == "" {
+		p.Print()
+	} else {
+		p.Print("\n", string(e)) // print extraneous leading newline
+	}
+	return nil
+}
+
 // formatError is an error implementing Format instead of errors.Formatter.
 // The implementation mimics the implementation of github.com/pkg/errors,
 // including that
diff --git a/errors/fmt/format.go b/errors/fmt/format.go
index 83872fe..f79301e 100644
--- a/errors/fmt/format.go
+++ b/errors/fmt/format.go
@@ -35,9 +35,10 @@
 	plusV  bool
 	sharpV bool
 
-	// error-related flags. plusV indicates detail mode.
-	inDetail bool
-	indent   bool
+	// error-related flags.
+	inDetail    bool
+	indent      bool
+	needNewline bool
 }
 
 // A fmt is the raw formatter used by Printf etc.