Skip to content

Treat any backslash-escaped character in a glob as a literal - #248

Merged
greut merged 1 commit into
editorconfig:masterfrom
gyanu2507:fix/glob-escapes
Oct 31, 2026
Merged

greut merged 1 commit into
editorconfig:masterfrom
gyanu2507:fix/glob-escapes

Conversation

@gyanu2507

Copy link
Copy Markdown
Contributor

The spec says special characters in a section name can be escaped with a backslash so they aren't treated as glob syntax. translate() only honoured that for } and , inside braces. Any other escaped character went through the normal glob handling, and the escape flag then stayed set for the next character.

Two visible effects:

root = true

[a\*]
k = v

editorconfig /tmp/x/abc prints k=v, because a\* becomes a[^/]*. It should only match a file literally named a*.

root = true

[\{a]
k = v

Every lookup in that directory fails:

cannot get definition for "/abc": filename match failed: error compiling "/**/\{a": error parsing regexp: missing closing ): `^(?:/|/.*/)(?:a$`

So one escaped { (or [) in a section name stops the whole .editorconfig from applying. The C core (0.12.11) and editorconfig-core-js handle both cases as literals.

Change

At the top of the loop in translate(), a character that follows a backslash is written with regexp.QuoteMeta and the glob switch is skipped. The isEscaped checks inside the }, , and default cases could no longer be reached, so I removed them and gave \\ its own case. That also let the maintidx entry come out of the nolint comment, since nolintlint flagged it as unused.

One existing expectation in TestTranslate changes: {e,\},f} now translates to (?:e|\}|f) instead of (?:e|}|f). Both match the same strings.

Tests

  • TestTranslate: new cases for escaped *, ?, { and \.
  • TestFnmatchCaseEscapes: checks that a\*, a\?, \{a, \{a,b} and a\[b] match the literal name and not a wildcard match. Without the change in fnmatch.go, 7 of these subtests fail.

go test ./... and make test-core (176 of 176) pass. golangci-lint run reports the same 10 issues as on master and nothing new.

I found this by comparing this core, the C core and the JS core on random section names and paths. After this change, the only differences left with the C core are cases where Go and JS agree with each other, like reversed numeric ranges such as {12..1}.

translate() only honoured an escape for } and , inside braces. An
escaped *, ?, [ or { was still translated as a glob operator, and the
escape then carried over to the next character. So [a\*] matched
"abc", and [\{a] produced an unbalanced regexp that made every lookup
in that directory fail with "error parsing regexp: missing closing )".

Emit the character after a backslash literally before looking at
glob syntax, as the spec describes and the C and JavaScript cores do.
@greut

greut commented Oct 15, 2026

Copy link
Copy Markdown
Member

@gyanu2507 thanks; we've got too many disabled tests.

@gyanu2507

Copy link
Copy Markdown
Contributor Author

@greut fair point. This PR does not add any new skipped cases: make test-core still runs 176/176, and the change only extends the existing Go unit coverage for escaped globs.

I am happy to take a follow-up that tries to enable some of the currently skipped parser cases (backslashed_*semicolon_or_hash_in_property, octothorpe_in_value, …) if you want that work queued separately from this glob-escape fix.

@greut
greut merged commit ab6b134 into editorconfig:master Oct 31, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants