Skip to content

LSP: Add support for custom file extensions#24463

Merged
MichaReiser merged 6 commits into
astral-sh:mainfrom
silverstein:codex/format-custom-extension-mapping
Apr 9, 2026
Merged

LSP: Add support for custom file extensions#24463
MichaReiser merged 6 commits into
astral-sh:mainfrom
silverstein:codex/format-custom-extension-mapping

Conversation

@silverstein

Copy link
Copy Markdown
Contributor

Summary

Honor the configured extension mapping when handling formatting requests in ruff server.

This fixes a case where a client sends a formatting request for a document whose file extension is mapped via Ruff configuration, e.g.:

[tool.ruff]
extension = { thing = "markdown" }

[tool.ruff.format]
preview = true

For a file like foo.thing, the CLI already formats correctly as Markdown, but ruff server was still deriving the source type from the raw file path and treating the document like Python during formatting.

Related: astral-sh/ruff-vscode#974

Root cause

The formatting request path was using query.source_type(), which derives the source type from the virtual file path alone.

That bypassed the configured extension mapping already available in settings.formatter.extension.

As a result, a markdown document with a custom mapped extension could be parsed as Python during a formatting request, which leads to warnings like:

Unable to format document: Got unexpected token ` at byte range 9..10

Changes

  • In full-document formatting, derive the source type from settings.formatter.extension.get_source_type(&file_path).
  • In range formatting, use the same formatter extension mapping for consistency.
  • Add a regression test that creates a temporary workspace with extension = { thing = "markdown" }, opens test.thing as a markdown document, and verifies that the formatting request returns edits instead of None.

Test plan

  • cargo test -p ruff_server custom_extension_mapped_to_markdown
  • cargo test -p ruff_server
  • cargo fmt --all --check

AI assistance

I used AI assistance for implementation and drafting, then reviewed the patch manually, reproduced the bug through both the VS Code extension path and a direct LSP request to ruff server, and ran the verification above.

@MichaReiser MichaReiser left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into this. I think we need the same handling for linting (and possibly other code paths) too.

.expect("time went backwards")
.as_nanos();
std::env::temp_dir().join(format!("ruff-server-{name}-{nanos}"))
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add tempdir as a dev-only dependency. It's what we use in all other tests.

@MichaReiser MichaReiser added the server Related to the LSP server label Apr 7, 2026

silverstein commented Apr 7, 2026

Copy link
Copy Markdown
Contributor Author

Thanks! I broadened the fix so it isn’t formatting-only anymore.

I moved the extension-mapping handling into the shared server request path so it now applies to:

  • formatting
  • range formatting
  • linting
  • fix-all
  • code actions
  • hover

Concretely, DocumentQuery now exposes mapping-aware source-type helpers for lint- and formatter-oriented operations, and the affected request paths use those instead of deriving the type from the raw filename alone.

I also added coverage for the expanded scope:

  • format_custom_extension_mapped_to_markdown
  • range_format_custom_extension_mapped_to_markdown_is_unsupported
  • lint_custom_extension_mapped_to_markdown_emits_no_diagnostics

Reran:

  • cargo test -p ruff_server
  • cargo fmt --all --check

The branch is updated now.

Comment thread crates/ruff_server/src/session/index.rs Outdated
Comment thread crates/ruff_server/src/fix.rs
Comment thread crates/ruff_server/src/server/api/requests/format_range.rs Outdated

silverstein commented Apr 8, 2026

Copy link
Copy Markdown
Contributor Author

Good catch, thank you. I removed the expect-based path instead of trying to justify it.

The updated shape is:

  • first resolve a mapping-aware source type for the operation (source_type_for_lint / source_type_for_format)
  • then only construct a Python SourceKind after we’ve already matched on SourceType::Python(...)

That makes the control flow explicit and avoids assuming that SourceKind::from_source_code(...) can never return None or a non-Python kind in the lint/fix path.

I pushed that cleanup in 4e42250cb9 and reran:

  • cargo test -p ruff_server
  • cargo fmt --all --check

Still green.

@MichaReiser

Copy link
Copy Markdown
Member

Can you confirm that you read our AI policy (https://github.com/astral-sh/.github/blob/main/AI_POLICY.md). I'm asking because I'm getting the impression that I'm chatting with an agent

@silverstein

Copy link
Copy Markdown
Contributor Author

I hadn't, sorry about that Micha! I did have codex help me clean up my reply so it was clearer. I'm a real person, so happy to clean anything up if you need.

@silverstein silverstein force-pushed the codex/format-custom-extension-mapping branch from 4e42250 to 1414235 Compare April 8, 2026 18:56
@MichaReiser MichaReiser changed the title fix(server): honor extension mapping for formatting LSP: Add support for custom extensions Apr 9, 2026
@astral-sh-bot

astral-sh-bot Bot commented Apr 9, 2026

Copy link
Copy Markdown

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

@MichaReiser MichaReiser force-pushed the codex/format-custom-extension-mapping branch from 5e70205 to 701b4ad Compare April 9, 2026 08:29
@MichaReiser MichaReiser enabled auto-merge (squash) April 9, 2026 08:30
@MichaReiser MichaReiser changed the title LSP: Add support for custom extensions LSP: Add support for custom file extensions Apr 9, 2026
@MichaReiser MichaReiser merged commit d8bc700 into astral-sh:main Apr 9, 2026
43 checks passed
ibraheemdev pushed a commit that referenced this pull request Apr 15, 2026
Co-authored-by: Micha Reiser <micha@reiser.io>
nicopauss pushed a commit to Intersec/lib-common that referenced this pull request Jun 4, 2026
##### [\`v0.15.10\`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#01510)

Released on 2026-04-09.

##### Preview features

- \[`flake8-logging`] Allow closures in except handlers (`LOG004`) ([#24464](astral-sh/ruff#24464))
- \[`flake8-self`] Make `SLF` diagnostics robust to non-self-named variables ([#24281](astral-sh/ruff#24281))
- \[`flake8-simplify`] Make the fix for `collapsible-if` safe in `preview` (`SIM102`) ([#24371](astral-sh/ruff#24371))

##### Bug fixes

- Avoid emitting multi-line f-string elements before Python 3.12 ([#24377](astral-sh/ruff#24377))
- Avoid syntax error from `E502` fixes in f-strings and t-strings ([#24410](astral-sh/ruff#24410))
- Strip form feeds from indent passed to `dedent_to` ([#24381](astral-sh/ruff#24381))
- \[`pyupgrade`] Fix panic caused by handling of octals (`UP012`) ([#24390](astral-sh/ruff#24390))
- Reject multi-line f-string elements before Python 3.12 ([#24355](astral-sh/ruff#24355))

##### Rule changes

- \[`ruff`] Treat f-string interpolation as potential side effect (`RUF019`) ([#24426](astral-sh/ruff#24426))

##### Server

- Add support for custom file extensions ([#24463](astral-sh/ruff#24463))

##### Documentation

- Document adding fixes in CONTRIBUTING.md ([#24393](astral-sh/ruff#24393))
- Fix JSON typo in settings example ([#24517](astral-sh/ruff#24517))

##### Contributors

- [@charliermarsh](https://github.com/charliermarsh)
- [@dylwil3](https://github.com/dylwil3)
- [@silverstein](https://github.com/silverstein)
- [@anishgirianish](https://github.com/anishgirianish)
- [@shizukushq](https://github.com/shizukushq)
- [@zanieb](https://github.com/zanieb)
- [@AlexWaygood](https://github.com/AlexWaygood)
##### [\`v0.15.9\`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#0159)

Released on 2026-04-02.

##### Preview features

- \[`pyflakes`] Flag annotated variable redeclarations as `F811` in preview mode ([#24244](astral-sh/ruff#24244))
- \[`ruff`] Allow dunder-named assignments in non-strict mode for `RUF067` ([#24089](astral-sh/ruff#24089))

##### Bug fixes

- \[`flake8-errmsg`] Avoid shadowing existing `msg` in fix for `EM101` ([#24363](astral-sh/ruff#24363))
- \[`flake8-simplify`] Ignore pre-initialization references in `SIM113` ([#24235](astral-sh/ruff#24235))
- \[`pycodestyle`] Fix `W391` fixes for consecutive empty notebook cells ([#24236](astral-sh/ruff#24236))
- \[`pyupgrade`] Fix `UP008` nested class matching ([#24273](astral-sh/ruff#24273))
- \[`pyupgrade`] Ignore strings with string-only escapes (`UP012`) ([#16058](astral-sh/ruff#16058))
- \[`ruff`] `RUF072`: skip formfeeds on dedent ([#24308](astral-sh/ruff#24308))
- \[`ruff`] Avoid re-using symbol in `RUF024` fix ([#24316](astral-sh/ruff#24316))
- \[`ruff`] Parenthesize expression in `RUF050` fix ([#24234](astral-sh/ruff#24234))
- Disallow starred expressions as values of starred expressions ([#24280](astral-sh/ruff#24280))

##### Rule changes

- \[`flake8-simplify`] Suppress `SIM105` for `except*` before Python 3.12 ([#23869](astral-sh/ruff#23869))
- \[`pyflakes`] Extend `F507` to flag `%`-format strings with zero placeholders ([#24215](astral-sh/ruff#24215))
- \[`pyupgrade`] `UP018` should detect more unnecessarily wrapped literals (UP018) ([#24093](astral-sh/ruff#24093))
- \[`pyupgrade`] Fix `UP008` callable scope handling to support lambdas ([#24274](astral-sh/ruff#24274))
- \[`ruff`] `RUF010`: Mark fix as unsafe when it deletes a comment ([#24270](astral-sh/ruff#24270))

##### Formatter

- Add `nested-string-quote-style` formatting option ([#24312](astral-sh/ruff#24312))

##### Documentation

- \[`flake8-bugbear`] Clarify RUF071 fix safety for non-path string comparisons ([#24149](astral-sh/ruff#24149))
- \[`flake8-type-checking`] Clarify import cycle wording for `TC001`/`TC002`/`TC003` ([#24322](astral-sh/ruff#24322))

##### Other changes

- Avoid rendering fix lines with trailing whitespace after `|` ([#24343](astral-sh/ruff#24343))

##### Contributors

- [@charliermarsh](https://github.com/charliermarsh)
- [@MichaReiser](https://github.com/MichaReiser)
- [@tranhoangtu-it](https://github.com/tranhoangtu-it)
- [@dylwil3](https://github.com/dylwil3)
- [@zsol](https://github.com/zsol)
- [@renovate](https://github.com/renovate)
- [@bitloi](https://github.com/bitloi)
- [@danparizher](https://github.com/danparizher)
- [@chinar-amrutkar](https://github.com/chinar-amrutkar)
- [@second-ed](https://github.com/second-ed)
- [@getehen](https://github.com/getehen)
- [@Redovo1](https://github.com/Redovo1)
- [@matthewlloyd](https://github.com/matthewlloyd)
- [@zanieb](https://github.com/zanieb)
- [@InSyncWithFoo](https://github.com/InSyncWithFoo)
- [@RenzoMXD](https://github.com/RenzoMXD)

Renovate-Branch: renovate/2024.6-ruff-0.15.x
Change-Id: Id4bd542d4f128b509284d9dcda312f2b39c29964
Priv-Id: 28ebcacdeffa50cec7a52eee59091a75ca5e9539
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

server Related to the LSP server

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants