Skip to content

Folding: a table is collapsed into a sibling whose key is a raw text-prefix of it ([fruit] swallows [fruit_juice]) #880

Description

@hamini-dev

Environment

  • Even Better TOML (VS Code) v0.21.2, bundled Taplo LSP
  • Reproduced against crates/taplo-lsp/src/handlers/folding_ranges.rs on master

Description

The folding-range builder decides whether table B is nested inside table A using a raw string prefix check on the dotted keys. This is intended to nest dotted children ([server] → [server.http]), but it also matches sibling tables that merely share a textual prefix, because there's no key-segment/. boundary in the test.

As a result, when you fold-all (Ctrl+K Ctrl+0), the sibling table's header is folded inside the shorter-named table and becomes invisible.

Minimal reproduction (repro.toml)

`[fruit]
color = "red"

[fruit_juice]
sugar = true`

Fold all. [fruit_juice] disappears — it is folded into [fruit]'s range. Renaming fruit_juice to e.g. juice (not prefixed by fruit) makes it behave correctly. The same happens with arrays of tables ([[a.well]] vs [[a.well_log]]).

Root cause

In create_folding_ranges (folding_ranges.rs), on each new header:

if k == &key || !key.starts_with(k) { // close k's fold false } else { // keep k open → nest the new header inside k true }

"fruit_juice".starts_with("fruit") is true, so fruit_juice is treated as a child of fruit.

Suggested fix

Only treat key as a descendant of k when k is followed by a key separator, i.e. require a . boundary:
`let is_descendant = key.len() > k.len()
&& key.starts_with(k)
&& key.as_bytes()[k.len()] == b'.';

if k == &key || !is_descendant {
// close k's fold
false
} else {
true
}`

(A more robust variant would compare parsed key segments rather than raw text, which would also handle quoted keys and dotted whitespace like a . b.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions