fix: pipe diagnostics highlight only the pipe and arguments.

This commit is contained in:
Spencer Brower
2026-08-10 17:08:26 -04:00
parent 6c09c73eb3
commit 3cb20b55e8
2 changed files with 39 additions and 21 deletions
+3 -3
View File
@@ -162,7 +162,7 @@ expected: |
9 | href="https://edwardtufte.github.io/tufte-css/">Tufte CSS</a> 9 | href="https://edwardtufte.github.io/tufte-css/">Tufte CSS</a>
10 | </p> 10 | </p>
11 | <p><small>&copy;</small> {{now | group_by }} {{params.author.name}}</p> 11 | <p><small>&copy;</small> {{now | group_by }} {{params.author.name}}</p>
| ^^^^^^^^^ missing argument | ^^^^^^^^ missing argument
12 | </footer> 12 | </footer>
| |
--- ---
@@ -303,7 +303,7 @@ input: |
<ul>{{#items | first 0}}<li>{{.}}</li>{{/items}}</ul> <ul>{{#items | first 0}}<li>{{.}}</li>{{/items}}</ul>
expected: | expected: |
argument must not be zero argument must not be zero
--> <test>:1:5 --> <test>:1:16
| |
1 | <ul>{{#items | first 0}}<li>{{.}}</li>{{/items}}</ul> 1 | <ul>{{#items | first 0}}<li>{{.}}</li>{{/items}}</ul>
| ^^^^^^^ | ^^^^^^^
@@ -317,7 +317,7 @@ input: |
<ul>{{#items | first -3}}<li>{{.}}</li>{{/items}}</ul> <ul>{{#items | first -3}}<li>{{.}}</li>{{/items}}</ul>
expected: | expected: |
first -3 is equivalent to last 3 first -3 is equivalent to last 3
--> <test>:1:5 --> <test>:1:16
| |
1 | <ul>{{#items | first -3}}<li>{{.}}</li>{{/items}}</ul> 1 | <ul>{{#items | first -3}}<li>{{.}}</li>{{/items}}</ul>
| ^^^^^^^^ consider using the clearer form | ^^^^^^^^ consider using the clearer form
+29 -11
View File
@@ -63,6 +63,7 @@ Pipe_Filter :: struct {
op: string, op: string,
args: [dynamic; MAX_PIPE_ARGS]string, args: [dynamic; MAX_PIPE_ARGS]string,
op_pos: int, op_pos: int,
end_pos: int,
} }
Group :: struct { Group :: struct {
@@ -199,6 +200,7 @@ parse_pipeline :: proc(
filter := Pipe_Filter { filter := Pipe_Filter {
op = tokens[0], op = tokens[0],
op_pos = content_base + op_offset_in_content, op_pos = content_base + op_offset_in_content,
end_pos = content_base + op_offset_in_content + len(seg),
} }
for j in 1 ..< len(tokens) { for j in 1 ..< len(tokens) {
append(&filter.args, tokens[j]) append(&filter.args, tokens[j])
@@ -297,7 +299,8 @@ apply_filter :: proc(
switch op { switch op {
case .Group_By: case .Group_By:
return apply_group_by(value, filter.args[:], pos) span := filter.end_pos - filter.op_pos
return apply_group_by(value, filter.args[:], filter.op_pos, span)
case .Format: case .Format:
str, ok := reflect.as_string(value) str, ok := reflect.as_string(value)
if !ok { if !ok {
@@ -337,9 +340,11 @@ apply_filter :: proc(
return any{new_clone(str2, context.temp_allocator), typeid_of(string)}, nil return any{new_clone(str2, context.temp_allocator), typeid_of(string)}, nil
} }
case .First: case .First:
return take(value, filter.args[:], true, tmpl, pos, filter.op_pos) span := filter.end_pos - filter.op_pos
return take(value, filter.args[:], true, tmpl, filter.op_pos, span)
case .Last: case .Last:
return take(value, filter.args[:], false, tmpl, pos, filter.op_pos) span := filter.end_pos - filter.op_pos
return take(value, filter.args[:], false, tmpl, filter.op_pos, span)
} }
return {}, nil return {}, nil
} }
@@ -381,19 +386,27 @@ apply_format :: proc(
} }
// Groups preserve first-appearance order from the input list. // Groups preserve first-appearance order from the input list.
apply_group_by :: proc(value: any, args: []string, pos: int) -> (result: any, err: Error) { apply_group_by :: proc(value: any, args: []string, pos: int, span: int) -> (result: any, err: Error) {
if len(args) != 1 { if len(args) != 1 {
hint := ""
if len(args) == 0 {
hint = "missing argument"
} else {
hint = "too many arguments"
}
return nil, Error_Body { return nil, Error_Body {
msg = fmt.tprintf("group_by expects 1 argument, got %d", len(args)), msg = fmt.tprintf("group_by expects 1 argument, got %d", len(args)),
pos = pos, pos = pos,
span = span,
kind = .Data, kind = .Data,
hint = hint,
} }
} }
field := args[0] field := args[0]
elem_info, count, data := list_info(value) elem_info, count, data := list_info(value)
if elem_info == nil { if elem_info == nil {
return nil, Error_Body{msg = "group_by expects a list", pos = pos, kind = .Data} return nil, Error_Body{msg = "group_by expects a list", pos = pos, span = span, kind = .Data}
} }
groups := make([dynamic]Group, 0, 8, context.temp_allocator) groups := make([dynamic]Group, 0, 8, context.temp_allocator)
@@ -441,8 +454,8 @@ take :: proc(
args: []string, args: []string,
from_start: bool, from_start: bool,
tmpl: Template, tmpl: Template,
tag_pos: int,
op_pos: int, op_pos: int,
span: int,
) -> ( ) -> (
any, any,
Error, Error,
@@ -458,7 +471,8 @@ take :: proc(
if !is_str { if !is_str {
return nil, Error_Body { return nil, Error_Body {
msg = "requires a list or string", msg = "requires a list or string",
pos = tag_pos, pos = op_pos,
span = span,
kind = .Data, kind = .Data,
source = tmpl.source, source = tmpl.source,
path = tmpl.path, path = tmpl.path,
@@ -472,7 +486,8 @@ take :: proc(
if !is_list && len(args) == 0 { if !is_list && len(args) == 0 {
warning = Error_Body { warning = Error_Body {
msg = "defaulting to n=1 for string", msg = "defaulting to n=1 for string",
pos = tag_pos, pos = op_pos,
span = span,
kind = .Warning, kind = .Warning,
source = tmpl.source, source = tmpl.source,
path = tmpl.path, path = tmpl.path,
@@ -484,7 +499,8 @@ take :: proc(
if !ok { if !ok {
return nil, Error_Body { return nil, Error_Body {
msg = fmt.tprintf("invalid argument '%s'", args[0]), msg = fmt.tprintf("invalid argument '%s'", args[0]),
pos = tag_pos, pos = op_pos,
span = span,
kind = .Data, kind = .Data,
source = tmpl.source, source = tmpl.source,
path = tmpl.path, path = tmpl.path,
@@ -496,7 +512,8 @@ take :: proc(
if n == 0 { if n == 0 {
return nil, Error_Body { return nil, Error_Body {
msg = "argument must not be zero", msg = "argument must not be zero",
pos = tag_pos, pos = op_pos,
span = span,
kind = .Data, kind = .Data,
source = tmpl.source, source = tmpl.source,
path = tmpl.path, path = tmpl.path,
@@ -508,7 +525,8 @@ take :: proc(
alt_name := from_start ? "last" : "first" alt_name := from_start ? "last" : "first"
warning = Error_Body { warning = Error_Body {
msg = fmt.tprintf("%s %d is equivalent to %s %d", op_name, n, alt_name, 0 - n), msg = fmt.tprintf("%s %d is equivalent to %s %d", op_name, n, alt_name, 0 - n),
pos = tag_pos, pos = op_pos,
span = span,
kind = .Warning, kind = .Warning,
source = tmpl.source, source = tmpl.source,
path = tmpl.path, path = tmpl.path,