feat: help for misspelled pipes is now shown to the user.

This commit is contained in:
Spencer Brower
2026-07-31 09:14:34 -04:00
parent 0d09db8d26
commit 9e93c012b6
4 changed files with 31 additions and 1 deletions
+1 -1
View File
@@ -326,5 +326,5 @@ format_render_error :: proc(err: Error, tmpl: Template, colorize: bool = false)
if path == "" { if path == "" {
path = "<input>" path = "<input>"
} }
return format_error(path, source, b.pos, b.msg, colorize = colorize, span = b.span) return format_error(path, source, b.pos, b.msg, hint = b.hint, colorize = colorize, span = b.span)
} }
+2
View File
@@ -32,6 +32,7 @@ Error_Body :: struct {
source: string, source: string,
path: string, path: string,
span: int, span: int,
hint: string,
} }
// Error is nil when no error occurred. // Error is nil when no error occurred.
@@ -59,6 +60,7 @@ tag_error :: proc(err: Error, tmpl: Template) -> Error {
msg = b.msg, msg = b.msg,
pos = b.pos, pos = b.pos,
span = b.span, span = b.span,
hint = b.hint,
kind = b.kind, kind = b.kind,
source = tmpl.source, source = tmpl.source,
path = tmpl.path, path = tmpl.path,
+6
View File
@@ -259,11 +259,17 @@ resolve_format_string :: proc(name: string, ctx: []any, pos: int) -> (string, Er
apply_filter :: proc(value: any, filter: ^Pipe_Filter, pos: int, ctx: []any) -> (any, Error) { apply_filter :: proc(value: any, filter: ^Pipe_Filter, pos: int, ctx: []any) -> (any, Error) {
op, ok := pipe_op_from_string(filter.op) op, ok := pipe_op_from_string(filter.op)
if !ok { if !ok {
hint := ""
suggestion := suggest_correction(pipe_op_candidates(), filter.op)
if suggestion != "" {
hint = fmt.tprintf("did you mean '%s'?", suggestion)
}
return nil, Error_Body { return nil, Error_Body {
msg = fmt.tprintf("unknown pipe op '%s'", filter.op), msg = fmt.tprintf("unknown pipe op '%s'", filter.op),
pos = filter.op_pos, pos = filter.op_pos,
span = len(filter.op), span = len(filter.op),
kind = .Data, kind = .Data,
hint = hint,
} }
} }
+22
View File
@@ -2,6 +2,7 @@
package mustache package mustache
import "core:fmt" import "core:fmt"
import "core:strings"
import "core:testing" import "core:testing"
import "core:time/datetime" import "core:time/datetime"
import "core:time/timezone" import "core:time/timezone"
@@ -561,3 +562,24 @@ test_format_mst_no_offset_no_timezone :: proc(t: ^testing.T) {
result, _ := render(tpl, data, {}, context.temp_allocator) result, _ := render(tpl, data, {}, context.temp_allocator)
testing.expect_value(t, result, "UTC") testing.expect_value(t, result, "UTC")
} }
// --- pipe op suggestion tests ---
@(test)
test_unknown_pipe_op_suggestion :: proc(t: ^testing.T) {
filter := Pipe_Filter{op = "formats", op_pos = 0}
_, err := apply_filter("2026-01-15", &filter, 0, nil)
testing.expect(t, err != nil, "should error on unknown op")
b := body(err)
testing.expect(t, strings.contains(b.hint, "format"), "hint should suggest 'format'")
testing.expect(t, strings.contains(b.hint, "did you mean"), "hint should be a suggestion")
}
@(test)
test_unknown_pipe_op_no_suggestion :: proc(t: ^testing.T) {
filter := Pipe_Filter{op = "xyz", op_pos = 0}
_, err := apply_filter("2026-01-15", &filter, 0, nil)
testing.expect(t, err != nil, "should error on unknown op")
b := body(err)
testing.expect(t, b.hint == "", "no suggestion expected for 'xyz'")
}