diff --git a/console/console.go b/console/console.go index 37c9f0afa..d10353093 100644 --- a/console/console.go +++ b/console/console.go @@ -182,7 +182,11 @@ func (c *Console) init(preload []string) error { // Preload any JavaScript files before starting the console for _, path := range preload { if err := c.jsre.Exec(path); err != nil { - return fmt.Errorf("%s: %v", path, jsErrorString(err)) + failure := err.Error() + if ottoErr, ok := err.(*otto.Error); ok { + failure = ottoErr.String() + } + return fmt.Errorf("%s: %v", path, failure) } } // Configure the console's input prompter for scrollback and tab completion @@ -269,7 +273,6 @@ func (c *Console) Evaluate(statement string) error { } }() if err := c.jsre.Evaluate(statement, c.printer); err != nil { - fmt.Fprintf(c.printer, "%v\n", jsErrorString(err)) return err } return nil @@ -359,11 +362,3 @@ func (c *Console) Stop(graceful bool) error { c.jsre.Stop(graceful) return nil } - -// jsErrorString adds a backtrace to errors generated by otto. -func jsErrorString(err error) string { - if ottoErr, ok := err.(*otto.Error); ok { - return ottoErr.String() - } - return err.Error() -} diff --git a/console/console_test.go b/console/console_test.go index 5d38331e8..72d3a2df6 100644 --- a/console/console_test.go +++ b/console/console_test.go @@ -281,3 +281,15 @@ func TestPrettyPrint(t *testing.T) { t.Fatalf("pretty print mismatch: have %s, want %s", output, want) } } + +// Tests that the JavaScript exceptions are properly formatted and colored. +func TestPrettyError(t *testing.T) { + tester := newTester(t, nil) + defer tester.Close(t) + tester.console.Evaluate("throw 'hello'") + + want := jsre.ErrorColor("hello") + "\n" + if output := string(tester.output.Bytes()); output != want { + t.Fatalf("pretty error mismatch: have %s, want %s", output, want) + } +} diff --git a/internal/jsre/jsre.go b/internal/jsre/jsre.go index 8d8f4fc2a..a95efd379 100644 --- a/internal/jsre/jsre.go +++ b/internal/jsre/jsre.go @@ -303,11 +303,11 @@ func (self *JSRE) Evaluate(code string, w io.Writer) error { self.Do(func(vm *otto.Otto) { val, err := vm.Run(code) if err != nil { - fail = err + prettyError(vm, err, w) } else { prettyPrint(vm, val, w) - fmt.Fprintln(w) } + fmt.Fprintln(w) }) return fail } diff --git a/internal/jsre/pretty.go b/internal/jsre/pretty.go index cf4bf2cf8..30d8660ff 100644 --- a/internal/jsre/pretty.go +++ b/internal/jsre/pretty.go @@ -37,6 +37,7 @@ var ( SpecialColor = color.New(color.Bold).SprintfFunc() NumberColor = color.New(color.FgRed).SprintfFunc() StringColor = color.New(color.FgGreen).SprintfFunc() + ErrorColor = color.New(color.FgHiRed).SprintfFunc() ) // these fields are hidden when printing objects. @@ -55,6 +56,23 @@ func prettyPrint(vm *otto.Otto, value otto.Value, w io.Writer) { ppctx{vm: vm, w: w}.printValue(value, 0, false) } +// prettyError writes err to standard output. +func prettyError(vm *otto.Otto, err error, w io.Writer) { + failure := err.Error() + if ottoErr, ok := err.(*otto.Error); ok { + failure = ottoErr.String() + } + fmt.Fprint(w, ErrorColor("%s", failure)) +} + +// jsErrorString adds a backtrace to errors generated by otto. +func jsErrorString(err error) string { + if ottoErr, ok := err.(*otto.Error); ok { + return ottoErr.String() + } + return err.Error() +} + func prettyPrintJS(call otto.FunctionCall, w io.Writer) otto.Value { for _, v := range call.ArgumentList { prettyPrint(call.Otto, v, w)