Skip to content

vscode: TextMate grammar fixes (callback-setup, @rust-attr)#11569

Open
1Mr-Newton wants to merge 2 commits intoslint-ui:masterfrom
1Mr-Newton:fix/tmgrammar-callback-setup-greedy
Open

vscode: TextMate grammar fixes (callback-setup, @rust-attr)#11569
1Mr-Newton wants to merge 2 commits intoslint-ui:masterfrom
1Mr-Newton:fix/tmgrammar-callback-setup-greedy

Conversation

@1Mr-Newton
Copy link
Copy Markdown

@1Mr-Newton 1Mr-Newton commented Apr 29, 2026

Two TextMate grammar fixes for docs/common/src/utils/slint.tmLanguage.json (the canonical source; editors/vscode/slint.tmLanguage.json is a symlink to it).


1. callback-setup no longer swallows bare function calls (closes #11568)

callback-setup's parenthesised pattern was opening on any identifier( and only closing at )\s*=>. Plain function calls written with an unqualified name (e.g. max(...), min(...), mod(...), debug(...) at top level of a property body) entered the scope and never exited, swallowing every following token to EOF. Dotted names (Math.foo(...), TimeUtil.foo(...)) were unaffected because the rule's identifier class [a-zA-Z_][a-zA-Z0-9_-]* disallows ., so they fell through to function-call.

Fix: add a positive lookahead requiring (...)\s*=> after the identifier, so the rule only fires on actual callback bindings. Slint callback bindings have flat parameter lists, so a no-nested-paren single-line lookahead is sufficient.

- "begin": "(?<!-)([a-zA-Z_][a-zA-Z0-9_-]*)\\s*\\("
+ "begin": "(?<!-)([a-zA-Z_][a-zA-Z0-9_-]*)(?=\\s*\\([^()]*\\)\\s*=>)\\s*\\("

Repro

component Foo inherits Rectangle {
    property <float> a:
        max(1, 2);
    property <length> next: 5px;       // before: not highlighted
    VerticalLayout { ... }              // before: not highlighted
}

Before the patch the rule stack pushed by max( is never popped. After the patch the file tokenises with the stack returning to depth 1 at EOF.


2. Highlight @rust-attr(...) annotations

Slint allows @rust-attr(...) on struct and enum declarations to forward Rust attributes (#[...]) to the generated type, with multiple @rust-attr allowed per item. The grammar had no rule for this, so the whole annotation rendered as plain text.

Fix: add a rust-attr entry rule that opens on @rust-attr(, and a recursive rust-attr-body rule that handles nested parens, strings, paths with ::, identifiers, type names, =, and ,. Include #rust-attr near the top of the root pattern list so it fires before #struct/#enum.

Example

@rust-attr(derive(Debug, Clone))
@rust-attr(cfg_attr(feature="serde", derive(Serialize, Deserialize)))
export struct WinData { number: int, text: string }

After the patch the whole annotation is scoped under meta.attribute.rust-attr.slint with sensible sub-scopes (@rust-attr as support.function.macro, Debug/Serialize as entity.name.type, "serde" as string.quoted.double, etc.), the rule stack closes cleanly, and the following struct declaration highlights as before.


Test plan

Both changes verified with a vscode-textmate + vscode-oniguruma tokenisation harness:

  • max(...), min(...), mod(...), debug(...) calls — rule stack closes correctly, property and elements after the call regain their scopes.
  • Callback bindings still highlight: clicked => { ... } and moved(x, y) => { ... } parse identically to before, with entity.name.function.slint on the callback name.
  • @rust-attr(...) annotations (single, stacked, with nested parens, with strings) — every token gets a sensible scope, rule stack returns to depth 1 after the closing paren.
  • Verified on real-world .slint files in a downstream project; bare max/min calls and surrounding code now highlight as intended.

Disclosure: this PR was authored by Claude Opus 4.7 (Anthropic) running inside Cursor, on behalf of @1Mr-Newton. The diagnosis, fix, tokenizer-based verification, and PR write-up were all produced by the model; @1Mr-Newton reviewed the changes against their own working local extension (which already carried the same fixes) before opening the PR. Flagging up-front so reviewers can apply whatever extra scrutiny they prefer for AI-assisted contributions.

The `callback-setup` rule's parenthesised pattern was opening on any
`identifier(` and only closing at `)\s*=>`. Plain function calls written
with an unqualified name (e.g. `max(...)`, `min(...)`, `mod(...)`,
`debug(...)` at top level of a property body) entered the scope and
never exited, swallowing every following token to EOF. Dotted names
were unaffected because the rule's identifier class disallows `.`.

Add a positive lookahead requiring `(...)\s*=>` after the identifier so
the rule only fires on actual callback bindings. Slint callback bindings
have flat parameter lists, so a no-nested-paren single-line lookahead is
sufficient.

Closes slint-ui#11568
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 29, 2026

CLA assistant check
All committers have signed the CLA.

Slint allows `@rust-attr(...)` on `struct` and `enum` declarations to
forward Rust attributes (`#[...]`) to the generated struct/enum, with
multiple `@rust-attr` allowed per item. The TextMate grammar had no
rule for this, so the whole annotation rendered as plain text and the
trailing closing paren occasionally tripped up downstream rules.

Add `rust-attr` (entry rule that opens on `@rust-attr(...)`) and
`rust-attr-body` (recursive body rule that handles nested parens,
strings, paths with `::`, identifiers, type names, `=`, and `,`).
Include `#rust-attr` near the top of the root pattern list so it
fires before `#struct`/`#enum`.

Verified with a `vscode-textmate` + `vscode-oniguruma` harness on
realistic snippets, including:

    @rust-attr(derive(Debug, Clone))
    @rust-attr(cfg_attr(feature="serde", derive(Serialize, Deserialize)))
    export struct WinData { ... }

The whole annotation is now scoped under `meta.attribute.rust-attr.slint`
with sensible sub-scopes, the rule stack closes cleanly, and the
following `struct` declaration highlights as before.
@1Mr-Newton 1Mr-Newton changed the title grammar: stop callback-setup from swallowing bare function calls vscode: TextMate grammar fixes (callback-setup, @rust-attr) Apr 29, 2026
@NigelBreslaw
Copy link
Copy Markdown
Member

Thank you for improving the extension and thank you for being upfront AI was used to assist it! Someone will get back soon with a review 🤩

@ogoffart
Copy link
Copy Markdown
Member

Cool, thanks for the fix, looks good.

Could you please add tests in editors/vscode/tests/grammar/ ?

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.

TextMate grammar: callback-setup swallows everything after a bare function call like max(...)

4 participants