Add test case and fix colorization bug for inline arrays in TOML

Co-authored-by: mikefarah <1151925+mikefarah@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-12-20 04:09:04 +00:00
parent c1b81f1a03
commit aa5134e645
2 changed files with 101 additions and 18 deletions

View File

@ -565,27 +565,50 @@ func (te *tomlEncoder) colorizeToml(input []byte) []byte {
}
// Table sections - [section] or [[array]]
// Only treat '[' as a table section if it appears at the start of the line
// (possibly after whitespace). This avoids mis-coloring inline arrays like
// "ports = [8000, 8001]" as table sections.
if ch == '[' {
end := i + 1
// Check for [[
if end < len(toml) && toml[end] == '[' {
end++
}
// Find closing ]
for end < len(toml) && toml[end] != ']' {
end++
}
// Include closing ]
if end < len(toml) {
end++
// Check for ]]
if end < len(toml) && toml[end] == ']' {
end++
isSectionHeader := true
if i > 0 {
isSectionHeader = false
j := i - 1
for j >= 0 && toml[j] != '\n' {
if toml[j] != ' ' && toml[j] != '\t' && toml[j] != '\r' {
// Found a non-whitespace character before this '[' on the same line,
// so this is not a table header.
break
}
j--
}
if j < 0 || toml[j] == '\n' {
// Reached the start of the string or a newline without encountering
// any non-whitespace, so '[' is at the logical start of the line.
isSectionHeader = true
}
}
result.WriteString(sectionColor(toml[i:end]))
i = end
continue
if isSectionHeader {
end := i + 1
// Check for [[
if end < len(toml) && toml[end] == '[' {
end++
}
// Find closing ]
for end < len(toml) && toml[end] != ']' {
end++
}
// Include closing ]
if end < len(toml) {
end++
// Check for ]]
if end < len(toml) && toml[end] == ']' {
end++
}
}
result.WriteString(sectionColor(toml[i:end]))
i = end
continue
}
}
// Strings - quoted text (double or single quotes)

View File

@ -3,8 +3,10 @@ package yqlib
import (
"bufio"
"fmt"
"strings"
"testing"
"github.com/fatih/color"
"github.com/mikefarah/yq/v4/test"
)
@ -625,3 +627,61 @@ func TestTomlScenarios(t *testing.T) {
}
documentScenarios(t, "usage", "toml", genericScenarios, documentTomlScenario)
}
// TestTomlColorization tests that colorization correctly distinguishes
// between table section headers and inline arrays
func TestTomlColorization(t *testing.T) {
// Test that inline arrays are not colored as table sections
encoder := &tomlEncoder{prefs: TomlPreferences{ColorsEnabled: true}}
// Create TOML with both table sections and inline arrays
input := []byte(`[database]
enabled = true
ports = [8000, 8001, 8002]
[servers]
alpha = "test"
`)
result := encoder.colorizeToml(input)
resultStr := string(result)
// The bug would cause the inline array [8000, 8001, 8002] to be
// colored with the section color (Yellow + Bold) instead of being
// left uncolored or colored differently.
//
// To test this, we check that the section color codes appear only
// for actual table sections, not for inline arrays.
// Get the ANSI codes for section color (Yellow + Bold)
sectionColor := color.New(color.FgYellow, color.Bold).SprintFunc()
sampleSection := sectionColor("[database]")
// Extract just the ANSI codes from the sample
// ANSI codes start with \x1b[
var ansiStart string
for i := 0; i < len(sampleSection); i++ {
if sampleSection[i] == '\x1b' {
// Find the end of the ANSI sequence (ends with 'm')
end := i
for end < len(sampleSection) && sampleSection[end] != 'm' {
end++
}
if end < len(sampleSection) {
ansiStart = sampleSection[i : end+1]
break
}
}
}
// Count how many times the section color appears in the output
// It should appear exactly twice: once for [database] and once for [servers]
// If it appears more times (e.g., for [8000, 8001, 8002]), that's the bug
sectionColorCount := strings.Count(resultStr, ansiStart)
// We expect exactly 2 occurrences (for [database] and [servers])
// The bug would cause more occurrences (e.g., also for [8000)
if sectionColorCount != 2 {
t.Errorf("Expected section color to appear exactly 2 times (for [database] and [servers]), but it appeared %d times.\nOutput: %s", sectionColorCount, resultStr)
}
}