From d15f1d131f8775c3e154b27185baf1b3870c8689 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 12 Apr 2026 12:26:40 +0000 Subject: [PATCH] fix parser error highlight offsets for non-suffix slices Co-authored-by: Thomas Pelletier --- errors_test.go | 21 +++++++++++++++++++++ unstable/parser.go | 19 ++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/errors_test.go b/errors_test.go index 3703bd0..014c164 100644 --- a/errors_test.go +++ b/errors_test.go @@ -286,6 +286,27 @@ func TestDecodeError_Position(t *testing.T) { } } +func TestDecodeError_InvalidKeyStartAfterComment(t *testing.T) { + doc := "# comment\n= \"value\"" + + var out map[string]string + err := Unmarshal([]byte(doc), &out) + assert.Error(t, err) + + var derr *DecodeError + if !errors.As(err, &derr) { + t.Fatal("error not in expected format") + } + + row, col := derr.Position() + assert.Equal(t, 2, row) + assert.Equal(t, 1, col) + assert.Equal(t, "toml: invalid character at start of key: =", derr.Error()) + assert.Equal(t, `1| # comment +2| = "value" + | ~ invalid character at start of key: =`, derr.String()) +} + func TestStrictErrorUnwrap(t *testing.T) { fo := bytes.NewBufferString(` Missing = 1 diff --git a/unstable/parser.go b/unstable/parser.go index e7c68dc..962cbfa 100644 --- a/unstable/parser.go +++ b/unstable/parser.go @@ -3,6 +3,7 @@ package unstable import ( "bytes" "fmt" + "reflect" "unicode" "github.com/pelletier/go-toml/v2/internal/characters" @@ -83,10 +84,22 @@ func (p *Parser) rangeOfToken(token, rest []byte) Range { } // subsliceOffset returns the byte offset of subslice b within p.data. -// b must be a suffix (tail) of p.data. +// b must share the same backing array as p.data. func (p *Parser) subsliceOffset(b []byte) int { - // b is a suffix of p.data, so its offset is len(p.data) - len(b) - return len(p.data) - len(b) + if len(b) == 0 { + // Most callers pass suffix slices, so preserve EOF behavior. + return len(p.data) + } + + dataPtr := reflect.ValueOf(p.data).Pointer() + subPtr := reflect.ValueOf(b).Pointer() + + offset := int(subPtr - dataPtr) + if offset < 0 || offset+len(b) > len(p.data) { + panic("subslice is not within parser input") + } + + return offset } // Raw returns the slice corresponding to the bytes in the given range.