Skip to content

feat: multiline array support to the toml parser - #176

Open
paval-shlyk wants to merge 4 commits into
saecki:mainfrom
paval-shlyk:fix-multiline-arrays
Open

paval-shlyk wants to merge 4 commits into
saecki:mainfrom
paval-shlyk:fix-multiline-arrays

Conversation

@paval-shlyk

@paval-shlyk paval-shlyk commented Feb 10, 2026 •

Copy link
Copy Markdown

Situation:

I'm using the crates.nvim Neovim plugin (tbh, my use case is very limited; I only use it for feature toggling and quick crate inspection). I'm also using the taplo LSP for formatting.
If a crate has many features, taplo will typically format them as a multi-line array (TOML v1.0 spec).
crates.nvim does not support multi-line arrays.

btw, taplo supports only the TOML v1.0 spec (see the issue). Therefore, we should not support 1.1 here either.

Target:

  • Update crates.nvim so interactive feature manipulation works with multi-line arrays.
  • Do not introduce any breaking changes.

Proposal:

Parser (lua/crates/toml.lua)

  • Detect an unclosed features = [ and accumulate lines until ]. Same path for table crates ([dependencies.foo]) and inline tables (foo = { ... }).
  • Record feat.end_line / feat.end_col at ]. For a single-line array they equal feat.line / feat.col.e.
  • Parse keys after ] on the closing line (], version = "1.2.3" }).
  • If the array is still open at the next assignment or EOF, keep the in-progress features and do not swallow the following crate.
  • Reject keys that only end with features (extra-features = [).
  • Require a closing ] in the single-line array patterns (it was optional).
  • Fallback: name = { with no complete inline table still starts a crate, so a multi-line features array on later lines can attach.
  • refresh_crate(buf, crate) re-parses the buffer and returns the crate with the same cache key.

Spans

  • TomlFeature.col / decl_col are absolute columns on TomlFeature.line, not offsets into feat.text.
  • decl_col is clamped to that line when leading/trailing whitespace sits on a neighbor.
  • Call sites (edit, diagnostic, popup, completion, actions) use feat.line + absolute columns. toml.feat_contains_line covers the full array range.

Edit (lua/crates/edit.lua)

  • insert_pos returns (line, col, before) so inserts of version / default-features / features work when the inline table already spans lines. col_to_insert remains as a column-only wrapper.
  • Enable on a multi-line array: trailing comma on the last item if missing; new item on its own line before ], indented like the last item.

Popup / completion / diagnostics

  • After a feature toggle, re-parse via refresh_crate instead of patching spans from the edited line.
  • Feature completion is offered on any line of the array.

Tests

  • Parse: table and inline multi-line arrays, features-before-version, unclosed array, extra-features false positive, diesel-style taplo output.
  • Edit: enable/disable, indent, two edits with refresh, insert default-features after a features-first array, remove array without a stray comma, extract into table, two features on one inner line.
  • Completion: quoted insert in array gaps; no extra quotes on an existing name.

Out of Scope

  • TOML 1.1 newlines between inline-table keys (foo = {\n version = "1",\n}). This branch only covers newlines inside the features array (valid in TOML 1.0, and what taplo emits).

All functionality is tested by me. Any feedback is welcome 😉

@saecki

saecki commented Feb 10, 2026

Copy link
Copy Markdown
Owner

Hey, thanks for this PR! I'll try to take a closer look and try this out this weekend.

I've noticed a few things right away. I don't think the case where inline-array items come after the multiline features array is handled. The type declaration of TomlCrateFeat and TomlFeature doesn't seem to be updated. The feature editing logic in edit.lua probably needs updating. Same for the popup code, which will also need to check for line numbers.

Somewhat related, with TOML 1.1 support landing in cargo, there is now also the possibility of multiline inline-tables. I'm not sure if that changes anything about this PR, just came to mind :)

@paval-shlyk

Copy link
Copy Markdown
Author

I believed that everything would be much simpler)

Honestly, I didn't even know that multiline inline-tables had been added.

@saecki

saecki commented Feb 12, 2026

Copy link
Copy Markdown
Owner

I believed that everything would be much simpler)

🫂

Honestly, I didn't even know that multiline inline-tables had been added.

Even if this PR "only" adds support for multi-line features, that would still be an improvement worth while :)

@paval-shlyk

Copy link
Copy Markdown
Author

@saecki. sorry for the delay (honestly, I completely forgot about this PR since I was using my branch). I pushed some changes recently because I wanted to make the PR feature complete. Sorry for the tremendous amount of changes (1k LoC is really huge for human beings 😢 ), but they are mostly tests.

Also updated the PR description. The proposal and changes are mostly machine-generated (since I don't want to invest too much time in Lua). But the code, at least, looks good to me 😉

@saecki

saecki commented Sep 17, 2026

Copy link
Copy Markdown
Owner

No worries, I'll try to find time this weekend to review this :)

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