Skip to content

Comments

Markdown formatting in LSP#23063

Merged
amyreese merged 4 commits intomainfrom
amy/lsp-markdown-formatting
Feb 9, 2026
Merged

Markdown formatting in LSP#23063
amyreese merged 4 commits intomainfrom
amy/lsp-markdown-formatting

Conversation

@amyreese
Copy link
Member

@amyreese amyreese commented Feb 3, 2026

  • Use SourceType in formatting related functions
  • Defer to ruff_markdown when formatting SourceType::Markdown
  • A bunch of todos around how to handle errors/etc

Tested against a local build of ruff-vscode extension modified to
declare support for markdown files, pointed at a local build of ruff

Demo:

2026-02-05.13-48-10.mov

Issue #22640

- Use `SourceType` in formatting related functions
- Defer to `ruff_markdown` when formatting `SourceType::Markdown`
- A bunch of `todos` around how to handle errors/etc

Tested against a local build of `ruff-vscode` extension modified to
declare support for markdown files, pointed at a local build of `ruff`

Issue #22640
@amyreese amyreese requested a review from ntBre February 3, 2026 23:06
@amyreese amyreese added formatter Related to the formatter preview Related to preview mode features server Related to the LSP server labels Feb 3, 2026
@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 3, 2026

Typing conformance results

No changes detected ✅

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 3, 2026

mypy_primer results

Changes were detected when running on open source projects
porcupine (https://github.com/Akuli/porcupine)
+ porcupine/pluginmanager.py:133:49: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Never]`, found `Unknown | str`
- Found 24 diagnostics
+ Found 25 diagnostics

Expression (https://github.com/cognitedata/Expression)
+ tests/test_compose.py:21:16: error[invalid-assignment] Object of type `(Never, /) -> Never` is not assignable to `(int, /) -> int`
- Found 200 diagnostics
+ Found 201 diagnostics

materialize (https://github.com/MaterializeInc/materialize)
+ misc/python/materialize/cli/mz_workload_anonymize.py:251:13: error[no-matching-overload] No overload of bound method `join` matches arguments
- Found 534 diagnostics
+ Found 535 diagnostics

sympy (https://github.com/sympy/sympy)
- sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic` is not assignable to `Expr | int | float | complex`
+ sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic | int | float | complex | Any` is not assignable to `Expr | int | float | complex`
- sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic` is not assignable to `Expr | int | float | complex`
+ sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic | int | float | complex | Any` is not assignable to `Expr | int | float | complex`
- sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic` is not assignable to `Expr | int | float | complex`
+ sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic | int | float | complex | Any` is not assignable to `Expr | int | float | complex`
- sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic` is not assignable to `Expr | int | float | complex`
+ sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic | int | float | complex | Any` is not assignable to `Expr | int | float | complex`
- sympy/functions/combinatorial/factorials.py:967:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/functions/combinatorial/factorials.py:967:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:968:29: warning[possibly-missing-attribute] Attribute `is_nonnegative` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:968:47: warning[possibly-missing-attribute] Attribute `is_integer` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:969:12: warning[possibly-missing-attribute] Attribute `is_zero` may be missing on object of type `Basic | int | float | complex | Any`
- sympy/functions/combinatorial/factorials.py:972:13: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic` and `Literal[1]`
+ sympy/functions/combinatorial/factorials.py:972:13: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
+ sympy/functions/combinatorial/factorials.py:975:12: warning[possibly-missing-attribute] Attribute `is_integer` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:976:16: warning[possibly-missing-attribute] Attribute `is_negative` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:978:18: warning[possibly-missing-attribute] Attribute `is_number` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:984:14: warning[possibly-missing-attribute] Attribute `is_number` may be missing on object of type `Basic | int | float | complex | Any`
- sympy/functions/combinatorial/factorials.py:986:26: error[unsupported-operator] Operator `+` is not supported between objects of type `Basic` and `Literal[1]`
+ sympy/functions/combinatorial/factorials.py:986:26: error[unsupported-operator] Operator `+` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
- sympy/functions/combinatorial/factorials.py:986:40: error[unsupported-operator] Operator `+` is not supported between objects of type `Basic` and `Literal[1]`
+ sympy/functions/combinatorial/factorials.py:986:40: error[unsupported-operator] Operator `+` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
- sympy/functions/combinatorial/factorials.py:986:53: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/functions/combinatorial/factorials.py:986:53: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/geometry/polygon.py:1500:12: warning[possibly-missing-attribute] Attribute `is_Number` may be missing on object of type `Basic | int | float | complex | Any`
- sympy/geometry/polygon.py:1501:20: error[invalid-argument-type] Argument to function `as_int` is incorrect: Expected `SupportsIndex`, found `Basic`
+ sympy/geometry/polygon.py:1501:20: error[invalid-argument-type] Argument to function `as_int` is incorrect: Expected `SupportsIndex`, found `Basic | int | float | complex | Any`
- sympy/geometry/polygon.py:1502:16: error[unsupported-operator] Operator `<` is not supported between objects of type `Basic` and `Literal[3]`
+ sympy/geometry/polygon.py:1502:16: error[unsupported-operator] Operator `<` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[3]`
+ sympy/geometry/polygon.py:1509:40: warning[possibly-missing-attribute] Attribute `is_number` may be missing on object of type `Basic | int | float | complex | Any`
- sympy/parsing/mathematica.py:692:38: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Never]`, found `Unknown | list[Unknown | str]`
- sympy/physics/optics/gaussopt.py:263:56: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:263:56: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:298:54: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:298:54: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:298:69: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:298:69: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:707:12: error[unsupported-operator] Operator `**` is not supported between objects of type `Basic` and `Literal[2]`
+ sympy/physics/optics/gaussopt.py:707:12: error[unsupported-operator] Operator `**` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[2]`
+ sympy/physics/optics/gaussopt.py:756:8: warning[possibly-missing-attribute] Attribute `is_infinite` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:756:25: warning[possibly-missing-attribute] Attribute `is_infinite` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:757:21: warning[possibly-missing-attribute] Attribute `is_infinite` may be missing on object of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:759:16: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:759:16: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:759:21: error[unsupported-operator] Operator `+` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:759:21: error[unsupported-operator] Operator `+` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:790:34: error[unsupported-operator] Unary operator `-` is not supported for object of type `Basic`
+ sympy/physics/optics/gaussopt.py:790:34: error[unsupported-operator] Unary operator `-` is not supported for object of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:837:30: error[unsupported-operator] Operator `**` is not supported between objects of type `Basic` and `Literal[2]`
+ sympy/physics/optics/gaussopt.py:837:30: error[unsupported-operator] Operator `**` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[2]`
- sympy/physics/optics/gaussopt.py:837:41: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:837:41: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:837:54: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[1]` and `Basic`
+ sympy/physics/optics/gaussopt.py:837:54: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[1]` and `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:838:22: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:838:22: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:838:37: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:838:37: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:839:31: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:839:31: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:839:46: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:839:46: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:887:9: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:887:9: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/quantum/cg.py:83:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
+ sympy/physics/quantum/cg.py:258:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
+ sympy/physics/quantum/cg.py:347:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:5997:12: warning[possibly-missing-attribute] Attribute `is_algebraic` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:5997:31: warning[possibly-missing-attribute] Attribute `is_irrational` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:5997:51: warning[possibly-missing-attribute] Attribute `is_algebraic` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:5997:70: warning[possibly-missing-attribute] Attribute `is_irrational` may be missing on object of type `Basic | int | float | complex | Any`
- sympy/polys/polytools.py:5998:20: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/polys/polytools.py:5998:20: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:6127:12: warning[possibly-missing-attribute] Attribute `is_algebraic` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:6127:31: warning[possibly-missing-attribute] Attribute `is_irrational` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:6127:51: warning[possibly-missing-attribute] Attribute `is_algebraic` may be missing on object of type `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:6127:70: warning[possibly-missing-attribute] Attribute `is_irrational` may be missing on object of type `Basic | int | float | complex | Any`
- sympy/polys/polytools.py:6128:20: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/polys/polytools.py:6128:20: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/series/formal.py:987:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
+ sympy/series/fourier.py:146:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
+ sympy/simplify/sqrtdenest.py:430:25: warning[possibly-missing-attribute] Attribute `subs` may be missing on object of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:361:32: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:361:32: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:362:20: error[unsupported-operator] Operator `>` is not supported between objects of type `Basic` and `Literal[1]`
+ sympy/stats/tests/test_finite_rv.py:362:20: error[unsupported-operator] Operator `>` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
- sympy/stats/tests/test_finite_rv.py:363:46: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:363:46: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:363:52: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:363:52: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:363:62: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:363:62: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:363:70: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic` and `Literal[1]`
+ sympy/stats/tests/test_finite_rv.py:363:70: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
- sympy/stats/tests/test_finite_rv.py:365:20: error[unsupported-operator] Operator `>` is not supported between objects of type `Basic` and `Literal[2]`
+ sympy/stats/tests/test_finite_rv.py:365:20: error[unsupported-operator] Operator `>` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[2]`
- sympy/stats/tests/test_finite_rv.py:365:30: error[unsupported-operator] Operator `<` is not supported between objects of type `Literal[0]` and `Basic`
+ sympy/stats/tests/test_finite_rv.py:365:30: error[unsupported-operator] Operator `<` is not supported between objects of type `Literal[0]` and `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:365:34: error[unsupported-operator] Operator `<` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:365:34: error[unsupported-operator] Operator `<` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:365:44: error[unsupported-operator] Operator `<` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:365:44: error[unsupported-operator] Operator `<` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:366:57: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `Basic`
+ sympy/stats/tests/test_finite_rv.py:366:57: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:366:67: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic` and `Literal[1]`
+ sympy/stats/tests/test_finite_rv.py:366:67: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
- sympy/stats/tests/test_finite_rv.py:366:79: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `Basic`
+ sympy/stats/tests/test_finite_rv.py:366:79: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:367:33: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:367:33: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:367:38: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:367:38: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:367:46: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:367:46: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:367:55: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic` and `Literal[2]`
+ sympy/stats/tests/test_finite_rv.py:367:55: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[2]`
- Found 15877 diagnostics
+ Found 15902 diagnostics

No memory usage changes detected ✅

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 3, 2026

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

@ntBre
Copy link
Contributor

ntBre commented Feb 4, 2026

This looks like a good start to me! It would be a good idea to get Dhruv's review once the todos are resolved too.

@amyreese amyreese force-pushed the amy/lsp-markdown-formatting branch from 4764eb2 to abe3115 Compare February 5, 2026 21:01
@amyreese amyreese requested a review from dhruvmanila February 5, 2026 21:01
@amyreese
Copy link
Member Author

amyreese commented Feb 5, 2026

Todos resolved by adding warnings and return Ok(None), similar to how syntax errors are handled.

@amyreese amyreese changed the title Prototype of markdown formatting in LSP Markdown formatting in LSP Feb 5, 2026
@amyreese amyreese linked an issue Feb 5, 2026 that may be closed by this pull request
Copy link
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

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

Makes sense to me, just two nits! It might be cool to have a screenshot or brief recording in the PR summary in lieu of a normal test plan.

@amyreese amyreese force-pushed the amy/lsp-markdown-formatting branch from abe3115 to 96a237e Compare February 5, 2026 21:48
@amyreese
Copy link
Member Author

amyreese commented Feb 5, 2026

Addressed feedback, added quick screen recording to summary

Copy link
Member

@dhruvmanila dhruvmanila left a comment

Choose a reason for hiding this comment

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

This looks good.

Is the intention to skip Jupyter Notebooks for the initial version as currently it won't work? To make it work, you'd need to add "markdown" cell syncing in

notebook_document_sync: Some(types::OneOf::Left(NotebookDocumentSyncOptions {
save: Some(false),
notebook_selector: [NotebookSelector::ByCells {
notebook: None,
cells: vec![NotebookCellSelector {
language: "python".to_string(),
}],
}]
.to_vec(),
})),
and I think that might have some side effects (or not). Because, that would inform the editors to notify the server about markdown cells as well.

Edit: It isn't supported from the CLI either so I'm assuming that it's planned as a follow-up instead.

Comment on lines +76 to +80
} else if let Some(LanguageId::Markdown) = language_id
&& formatter_settings.is_some()
{
tracing::debug!("Included path via Markdown language ID: {}", path.display());
false
Copy link
Member

Choose a reason for hiding this comment

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

Can you say why there's an additional check for whether formatter_settings.is_some() or not? Or is it because to check whether preview mode is enabled or not?

Copy link
Member Author

Choose a reason for hiding this comment

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

This was primarily to include Markdown files when formatting, but exclude them when linting (where the linter settings would be provided and formatter settings would be None).

@amyreese
Copy link
Member Author

amyreese commented Feb 9, 2026

Since we aren't formatting the Markdown style itself (only Python code blocks embedded in Markdown documents) formatting within notebook cells is not on the roadmap. I think it would be interesting to see if there are ecosystem cases where notebooks actually contain Markdown cells with embedded Python code blocks, and if they expect that ruff would format those embedded code blocks.

@amyreese amyreese merged commit bb62fc7 into main Feb 9, 2026
50 checks passed
@amyreese amyreese deleted the amy/lsp-markdown-formatting branch February 9, 2026 18:26
carljm added a commit to Hugo-Polloli/ruff that referenced this pull request Feb 9, 2026
* main: (45 commits)
  [ty] Fix wrong inlay hints for overloaded function arguments (astral-sh#23179)
  [ty] Respect `@no_type_check` when combined with other decorators (astral-sh#23177)
  [ty] Use type context when inferring constructor argument types (astral-sh#23139)
  [`airflow`] Add ruff rules to catch deprecated attribute access from context key for Airflow 3.0 (`AIR301`) (astral-sh#22850)
  Support formatting `pycon` markdown code blocks (astral-sh#23112)
  Markdown formatting in LSP (astral-sh#23063)
  Instruct Claude to use comments more sparingly (astral-sh#23181)
  [`flake8-gettext`] Fix false negatives for plural argument of ngettext (`INT001`, `INT002`, `INT003`) (astral-sh#21078)
  [ty] Invoking goto-def on parentheses of a class constructor call takes you too constructor method
  [ty] Make goto definition on class constructor always go to class definition
  [ty] Assign lower completions ranking to deprecated functions and classes (astral-sh#23089)
  [ty] Fix parameter references across files via keyword args (astral-sh#23012)
  [ty] Exclude enclosing class for base completions (astral-sh#23141)
  [`pyupgrade`] Fix syntax error on string with newline escape and comment (`UP037`) (astral-sh#22968)
  [ty] Improve documentation for `expect_single_definition` method (astral-sh#23175)
  [ty] Configure check mode for all projects
  Add `home-assistant` to ecosystem projects (astral-sh#23132)
  Add tabbed shell completion documentation (astral-sh#23169)
  Bump typing conformance-suite pin (astral-sh#23174)
  [ty] Fix invalid diagnostic location for a sub-call to a specialized ParamSpec (astral-sh#23036)
  ...
@dhruvmanila
Copy link
Member

I think it would be interesting to see if there are ecosystem cases where notebooks actually contain Markdown cells with embedded Python code blocks, and if they expect that ruff would format those embedded code blocks.

Yeah, that seems reasonable. I do realize that now as there wouldn't be too many examples of notebooks with markdown cells containing Python code in it 😅

amyreese added a commit to astral-sh/ruff-vscode that referenced this pull request Feb 10, 2026
Changes necessary to support markdown formatting in ruff's LSP in
vscode:
astral-sh/ruff#23063
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

formatter Related to the formatter preview Related to preview mode features server Related to the LSP server

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LSP formatting support for markdown files

3 participants