cmd/cue/cmd: always print newline at end of eval

format.Node doesn't print a newline after
a single expression.

Change-Id: I87220e0c2a290ffd7618c4633329d3ef614df834
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/3521
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/eval.go b/cmd/cue/cmd/eval.go
index bd70b73..befbc69 100644
--- a/cmd/cue/cmd/eval.go
+++ b/cmd/cue/cmd/eval.go
@@ -15,6 +15,7 @@
 package cmd
 
 import (
+	"bytes"
 	"fmt"
 
 	"cuelang.org/go/cue"
@@ -90,6 +91,14 @@
 	}
 
 	w := cmd.OutOrStdout()
+	// Always print a trailing newline. format.Node may not write a trailing
+	// newline if the output is single-line expression.
+	writeNode := func(b []byte, err error) {
+		_, _ = w.Write(b)
+		if !bytes.HasSuffix(b, []byte("\n")) {
+			w.Write([]byte{'\n'})
+		}
+	}
 
 	for _, inst := range instances {
 		// TODO: use ImportPath or some other sanitized path.
@@ -122,15 +131,12 @@
 					continue
 				}
 			}
-			b, _ := format.Node(getSyntax(v, syn), opts...)
-			_, _ = w.Write(b)
+			writeNode(format.Node(getSyntax(v, syn), opts...))
 		}
 		for _, e := range exprs {
 			if len(exprs) > 1 {
 				fmt.Fprint(w, "// ")
-				b, _ := format.Node(e)
-				_, _ = w.Write(b)
-				fmt.Fprintln(w)
+				writeNode(format.Node(e))
 			}
 			v := inst.Eval(e)
 			if flagConcrete.Bool(cmd) && !flagIgnore.Bool(cmd) {
@@ -139,9 +145,7 @@
 					continue
 				}
 			}
-			b, _ := format.Node(getSyntax(v, syn), opts...)
-			_, _ = w.Write(b)
-			fmt.Fprintln(w)
+			writeNode(format.Node(getSyntax(v, syn), opts...))
 		}
 	}
 	return nil
diff --git a/cmd/cue/cmd/testdata/script/eval_newline.txt b/cmd/cue/cmd/testdata/script/eval_newline.txt
new file mode 100644
index 0000000..948efe7
--- /dev/null
+++ b/cmd/cue/cmd/testdata/script/eval_newline.txt
@@ -0,0 +1,6 @@
+cue eval ./data.cue
+cmp stdout expect-stdout
+-- data.cue --
+3
+-- expect-stdout --
+3