fix: detect the rust-analyzer component in a multi-line components array - #22996
Conversation
| // Matches a `components` array that lists `rust-analyzer`. The elements are matched with | ||
| // `[^\]]` rather than `.` so that the array may be spread over several lines, which is just | ||
| // as valid TOML as keeping it on one. TOML strings come in both quote flavours. | ||
| const RA_COMPONENT_RE = /components\s*=\s*\[[^\]]*["']rust-analyzer["'][^\]]*\]/; |
There was a problem hiding this comment.
I'd prefer:
/components\s*=\s*\[(?<array>.*?)\]*\]/sThen checking if the capture group array contains rust-analyzer. The current regex is wrong when rust-analyzer appears in the rest of the file, not instead this array.
Of course my regex is also wrong, e.g. when rust-analyzer appears in a comment. Oh well. The only real fix is to pull a TOML parsing library, but I don't want to do this just for that. I guess my regex is enough for practical needs.
There was a problem hiding this comment.
I switched to the named capture group since it reads better. The previous [^\]]* also stopped at the closing ], so it could not match a rust-analyzer elsewhere in the file. I tightened the test to cover a quoted mention after the array, and kept the quote check instead of includes() so unquoted mentions do not count. Happy to change that too if you prefer.
Closes #22980
hasToolchainFileWithRaDeclaredmatched thecomponentsarray with.between thebrackets.
.does not match newlines, so an array written over several lines was neverdetected, even though rustup treats it identically to the single line form. Then extension
then fell back to the bundled server, and on a pinned toolchain older than the extension's
minimum supported version that produces a "toolchain too old" modal on every reload, with
nothing in the output channel explaining why the toolchain binary was skipped.
The elements are now matched with
[^\]]instead. It crosses newlines but still stops at theclosing bracket, so the match cannot run past the end of the array into an unrelated key. Two
smaller things came with it: TOML literal strings (
'rust-analyzer') are accepted, and theold `?.length === 1 is gone, and a file containing two matching arrays counted as no match
at all.
Selection behaviour is otherwise unchanged. Detection is still opt-in, only when
componentsexplicitly names
rust-analyzer, and precedence between the toolchain server and the bundledone is untouched. Having the component installed without declaring it still does not displace
the bundled server.
The predicate is split out as
declaresRaComponentand exposed through the existing_privateobject so it can be tested as a plain string check without mocking the filesystem. Tests cover
single line, multi line, literal strings, a components array without rust-analyzer, a file with
no components key, and rust-analyzer appearing outside the array.
🤖 AI-assisted: writing the tests and assisting in the fix