Skip to content

Commit

Permalink
Improve Katex error handling and fix handling of large expressions
Browse files Browse the repository at this point in the history
* Make throwOnError=true the new default
* Handle JS errors as part of the RPC request/response flow
* Return a new Result type with .Err on it

This enables constructs on the form:

```handlebars
{{ with transform.ToMath "c = \\foo{a^2 + b^2}" }}
	{{ with .Err }}
	 	{{ warnf "error: %s" . }}
	{{ else }}
		{{ . }}
	{{ end }}
{{ end }}
```

Note that the new `Result` type behaves like `template.HTML` (or a string if needed) when printed, but it will panic if in a error state.

Closes #12748
  • Loading branch information
bep committed Aug 12, 2024
1 parent e422635 commit e1e1baa
Show file tree
Hide file tree
Showing 14 changed files with 569 additions and 24 deletions.
24 changes: 24 additions & 0 deletions common/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,27 @@ var InvocationCounter atomic.Int64
func NewBool(b bool) *bool {
return &b
}

// PrintableValueProvider is implemented by types that can provide a printable value.
type PrintableValueProvider interface {
PrintableValue() any
}

var _ PrintableValueProvider = Result[any]{}

// Result is a generic result type.
type Result[T any] struct {
// The result value.
Value T

// The error value.
Err error
}

// PrintableValue returns the value or panics if there is an error.
func (r Result[T]) PrintableValue() any {
if r.Err != nil {
panic(r.Err)
}
return r.Value
}
12 changes: 11 additions & 1 deletion internal/warpc/js/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,23 @@ export function readInput(handle) {

currentLine = [...currentLine, ...buffer.subarray(0, bytesRead)];

// Check for newline. If not, we need to read more data.
if (!currentLine.includes(10)) {
continue;
}

// Split array into chunks by newline.
let i = 0;
for (let j = 0; i < currentLine.length; i++) {
if (currentLine[i] === 10) {
const chunk = currentLine.splice(j, i + 1);
const arr = new Uint8Array(chunk);
const json = JSON.parse(new TextDecoder().decode(arr));
let json;
try {
json = JSON.parse(new TextDecoder().decode(arr));
} catch (e) {
throw new Error(`Error parsing JSON '${new TextDecoder().decode(arr)}' from stdin: ${e.message}`);
}
handle(json);
j = i + 1;
}
Expand Down
4 changes: 2 additions & 2 deletions internal/warpc/js/greet.bundle.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 9 additions & 9 deletions internal/warpc/js/renderkatex.bundle.js

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion internal/warpc/js/renderkatex.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ const render = function (input) {
const data = input.data;
const expression = data.expression;
const options = data.options;
writeOutput({ header: input.header, data: { output: katex.renderToString(expression, options) } });
const header = input.header;
try {
const output = katex.renderToString(expression, options);
writeOutput({ header: header, data: { output: output } });
} catch (e) {
header.err = e.message;
writeOutput({ header: header });
}
};

readInput(render);
1 change: 0 additions & 1 deletion internal/warpc/katex.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ type KatexOptions struct {
MinRuleThickness float64 `json:"minRuleThickness"`

// If true, KaTeX will throw a ParseError when it encounters an unsupported command.
// For internal use only, for now.
ThrowOnError bool `json:"throwOnError"`
}

Expand Down
5 changes: 4 additions & 1 deletion internal/warpc/warpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ var quickjsWasm []byte
type Header struct {
Version string `json:"version"`
ID uint32 `json:"id"`

// Set in the response if there was an error.
Err string `json:"err"`
}

type Message[T any] struct {
Expand Down Expand Up @@ -179,7 +182,7 @@ func (d *dispatcher[Q, R]) input() {
for d.inOut.dec.More() {
var r Message[R]
if err := d.inOut.dec.Decode(&r); err != nil {
inputErr = err
inputErr = fmt.Errorf("decoding response: %w", err)
break
}

Expand Down
Binary file modified internal/warpc/wasm/greet.wasm
Binary file not shown.
Binary file modified internal/warpc/wasm/renderkatex.wasm
Binary file not shown.
3 changes: 2 additions & 1 deletion tpl/internal/go_templates/htmltemplate/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ const (

// indirect returns the value, after dereferencing as many times
// as necessary to reach the base type (or nil).
func indirect(a any) any {
// Signature modified by Hugo. TODO(bep) script this.
func doIndirect(a any) any {
if a == nil {
return nil
}
Expand Down
12 changes: 12 additions & 0 deletions tpl/internal/go_templates/htmltemplate/hugo_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package template

import (
"github.com/gohugoio/hugo/common/types"
template "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate"
)

Expand All @@ -39,3 +40,14 @@ func (t *Template) Prepare() (*template.Template, error) {
func StripTags(html string) string {
return stripTags(html)
}

func indirect(a any) any {
in := doIndirect(a)

// We have a special Result type that we want to unwrap when printed.
if pp, ok := in.(types.PrintableValueProvider); ok {
return pp.PrintableValue()
}

return in
}
Loading

0 comments on commit e1e1baa

Please sign in to comment.