@@ -2,10 +2,11 @@ use std::io::Write;
22use std:: path:: Path ;
33use std:: process:: { Command , Stdio } ;
44
5- use anyhow:: Context ;
5+ use anyhow:: { Context , Error } ;
66
77use ruff_formatter:: { FormatOptions , PrintedRange } ;
8- use ruff_python_ast:: PySourceType ;
8+ use ruff_markdown:: { MarkdownResult , format_code_blocks} ;
9+ use ruff_python_ast:: { PySourceType , SourceType } ;
910use ruff_python_formatter:: { FormatModuleError , PyFormatOptions , format_module_source} ;
1011use ruff_source_file:: LineIndex ;
1112use ruff_text_size:: TextRange ;
@@ -30,7 +31,7 @@ pub(crate) enum FormatBackend {
3031
3132pub ( crate ) fn format (
3233 document : & TextDocument ,
33- source_type : PySourceType ,
34+ source_type : SourceType ,
3435 formatter_settings : & FormatterSettings ,
3536 path : & Path ,
3637 backend : FormatBackend ,
@@ -44,47 +45,75 @@ pub(crate) fn format(
4445/// Format using the built-in Ruff formatter.
4546fn format_internal (
4647 document : & TextDocument ,
47- source_type : PySourceType ,
48+ source_type : SourceType ,
4849 formatter_settings : & FormatterSettings ,
4950 path : & Path ,
5051) -> crate :: Result < Option < String > > {
51- let format_options =
52- formatter_settings. to_format_options ( source_type, document. contents ( ) , Some ( path) ) ;
53- match format_module_source ( document. contents ( ) , format_options) {
54- Ok ( formatted) => {
55- let formatted = formatted. into_code ( ) ;
56- if formatted == document. contents ( ) {
57- Ok ( None )
58- } else {
59- Ok ( Some ( formatted) )
52+ match source_type {
53+ SourceType :: Python ( py_source_type) => {
54+ let format_options = formatter_settings. to_format_options (
55+ py_source_type,
56+ document. contents ( ) ,
57+ Some ( path) ,
58+ ) ;
59+ match format_module_source ( document. contents ( ) , format_options) {
60+ Ok ( formatted) => {
61+ let formatted = formatted. into_code ( ) ;
62+ if formatted == document. contents ( ) {
63+ Ok ( None )
64+ } else {
65+ Ok ( Some ( formatted) )
66+ }
67+ }
68+ // Special case - syntax/parse errors are handled here instead of
69+ // being propagated as visible server errors.
70+ Err ( FormatModuleError :: ParseError ( error) ) => {
71+ tracing:: warn!( "Unable to format document: {error}" ) ;
72+ Ok ( None )
73+ }
74+ Err ( err) => Err ( err. into ( ) ) ,
6075 }
6176 }
62- // Special case - syntax/parse errors are handled here instead of
63- // being propagated as visible server errors.
64- Err ( FormatModuleError :: ParseError ( error) ) => {
65- tracing:: warn!( "Unable to format document: {error}" ) ;
66- Ok ( None )
77+ SourceType :: Markdown => {
78+ if !formatter_settings. preview . is_enabled ( ) {
79+ return Ok ( None ) ; // todo
80+ }
81+
82+ match format_code_blocks ( document. contents ( ) , Some ( path) , formatter_settings) {
83+ MarkdownResult :: Formatted ( formatted) => Ok ( Some ( formatted) ) ,
84+ MarkdownResult :: Unchanged => Ok ( None ) ,
85+ }
6786 }
68- Err ( err ) => Err ( err . into ( ) ) ,
87+ SourceType :: Toml ( _ ) => Ok ( None ) , // todo
6988 }
7089}
7190
7291/// Format using an external uv command.
7392fn format_external (
7493 document : & TextDocument ,
75- source_type : PySourceType ,
94+ source_type : SourceType ,
7695 formatter_settings : & FormatterSettings ,
7796 path : & Path ,
7897) -> crate :: Result < Option < String > > {
79- let format_options =
80- formatter_settings. to_format_options ( source_type, document. contents ( ) , Some ( path) ) ;
81- let uv_command = UvFormatCommand :: from ( format_options) ;
82- uv_command. format_document ( document. contents ( ) , path)
98+ match source_type {
99+ SourceType :: Python ( py_source_type) => {
100+ let format_options = formatter_settings. to_format_options (
101+ py_source_type,
102+ document. contents ( ) ,
103+ Some ( path) ,
104+ ) ;
105+ let uv_command = UvFormatCommand :: from ( format_options) ;
106+ uv_command. format_document ( document. contents ( ) , path)
107+ }
108+ SourceType :: Markdown | SourceType :: Toml ( _) => {
109+ Ok ( None ) // todo
110+ }
111+ }
83112}
84113
85114pub ( crate ) fn format_range (
86115 document : & TextDocument ,
87- source_type : PySourceType ,
116+ source_type : SourceType ,
88117 formatter_settings : & FormatterSettings ,
89118 range : TextRange ,
90119 path : & Path ,
@@ -103,48 +132,68 @@ pub(crate) fn format_range(
103132/// Format range using the built-in Ruff formatter
104133fn format_range_internal (
105134 document : & TextDocument ,
106- source_type : PySourceType ,
135+ source_type : SourceType ,
107136 formatter_settings : & FormatterSettings ,
108137 range : TextRange ,
109138 path : & Path ,
110139) -> crate :: Result < Option < PrintedRange > > {
111- let format_options =
112- formatter_settings. to_format_options ( source_type, document. contents ( ) , Some ( path) ) ;
113-
114- match ruff_python_formatter:: format_range ( document. contents ( ) , range, format_options) {
115- Ok ( formatted) => {
116- if formatted. as_code ( ) == document. contents ( ) {
117- Ok ( None )
118- } else {
119- Ok ( Some ( formatted) )
140+ match source_type {
141+ SourceType :: Python ( py_source_type) => {
142+ let format_options = formatter_settings. to_format_options (
143+ py_source_type,
144+ document. contents ( ) ,
145+ Some ( path) ,
146+ ) ;
147+
148+ match ruff_python_formatter:: format_range ( document. contents ( ) , range, format_options) {
149+ Ok ( formatted) => {
150+ if formatted. as_code ( ) == document. contents ( ) {
151+ Ok ( None )
152+ } else {
153+ Ok ( Some ( formatted) )
154+ }
155+ }
156+ // Special case - syntax/parse errors are handled here instead of
157+ // being propagated as visible server errors.
158+ Err ( FormatModuleError :: ParseError ( error) ) => {
159+ tracing:: warn!( "Unable to format document range: {error}" ) ;
160+ Ok ( None )
161+ }
162+ Err ( err) => Err ( err. into ( ) ) ,
120163 }
121164 }
122- // Special case - syntax/parse errors are handled here instead of
123- // being propagated as visible server errors.
124- Err ( FormatModuleError :: ParseError ( error) ) => {
125- tracing:: warn!( "Unable to format document range: {error}" ) ;
126- Ok ( None )
165+ SourceType :: Markdown | SourceType :: Toml ( _) => {
166+ Ok ( None ) // todo
127167 }
128- Err ( err) => Err ( err. into ( ) ) ,
129168 }
130169}
131170
132171/// Format range using an external command, i.e., `uv`.
133172fn format_range_external (
134173 document : & TextDocument ,
135- source_type : PySourceType ,
174+ source_type : SourceType ,
136175 formatter_settings : & FormatterSettings ,
137176 range : TextRange ,
138177 path : & Path ,
139178) -> crate :: Result < Option < PrintedRange > > {
140- let format_options =
141- formatter_settings. to_format_options ( source_type, document. contents ( ) , Some ( path) ) ;
142- let uv_command = UvFormatCommand :: from ( format_options) ;
143-
144- // Format the range using uv and convert the result to `PrintedRange`
145- match uv_command. format_range ( document. contents ( ) , range, path, document. index ( ) ) ? {
146- Some ( formatted) => Ok ( Some ( PrintedRange :: new ( formatted, range) ) ) ,
147- None => Ok ( None ) ,
179+ match source_type {
180+ SourceType :: Python ( py_source_type) => {
181+ let format_options = formatter_settings. to_format_options (
182+ py_source_type,
183+ document. contents ( ) ,
184+ Some ( path) ,
185+ ) ;
186+ let uv_command = UvFormatCommand :: from ( format_options) ;
187+
188+ // Format the range using uv and convert the result to `PrintedRange`
189+ match uv_command. format_range ( document. contents ( ) , range, path, document. index ( ) ) ? {
190+ Some ( formatted) => Ok ( Some ( PrintedRange :: new ( formatted, range) ) ) ,
191+ None => Ok ( None ) ,
192+ }
193+ }
194+ SourceType :: Markdown | SourceType :: Toml ( _) => {
195+ Ok ( None ) // todo
196+ }
148197 }
149198}
150199
@@ -327,7 +376,7 @@ mod tests {
327376
328377 use insta:: assert_snapshot;
329378 use ruff_linter:: settings:: types:: { CompiledPerFileTargetVersionList , PerFileTargetVersion } ;
330- use ruff_python_ast:: { PySourceType , PythonVersion } ;
379+ use ruff_python_ast:: { PySourceType , PythonVersion , SourceType } ;
331380 use ruff_text_size:: { TextRange , TextSize } ;
332381 use ruff_workspace:: FormatterSettings ;
333382
@@ -349,7 +398,7 @@ with open("a_really_long_foo") as foo, open("a_really_long_bar") as bar, open("a
349398 . unwrap ( ) ;
350399 let result = format (
351400 & document,
352- PySourceType :: Python ,
401+ SourceType :: Python ( PySourceType :: Python ) ,
353402 & FormatterSettings {
354403 unresolved_target_version : PythonVersion :: PY38 ,
355404 per_file_target_version,
@@ -373,7 +422,7 @@ with open("a_really_long_foo") as foo, open("a_really_long_bar") as bar, open("a
373422 // same as above but without the per_file_target_version override
374423 let result = format (
375424 & document,
376- PySourceType :: Python ,
425+ SourceType :: Python ( PySourceType :: Python ) ,
377426 & FormatterSettings {
378427 unresolved_target_version : PythonVersion :: PY38 ,
379428 ..Default :: default ( )
@@ -420,7 +469,7 @@ sys.exit(
420469 . unwrap ( ) ;
421470 let result = format_range (
422471 & document,
423- PySourceType :: Python ,
472+ SourceType :: Python ( PySourceType :: Python ) ,
424473 & FormatterSettings {
425474 unresolved_target_version : PythonVersion :: PY38 ,
426475 per_file_target_version,
@@ -445,7 +494,7 @@ sys.exit(
445494 // same as above but without the per_file_target_version override
446495 let result = format_range (
447496 & document,
448- PySourceType :: Python ,
497+ SourceType :: Python ( PySourceType :: Python ) ,
449498 & FormatterSettings {
450499 unresolved_target_version : PythonVersion :: PY38 ,
451500 ..Default :: default ( )
@@ -488,7 +537,7 @@ def world( ):
488537
489538 let result = format (
490539 & document,
491- PySourceType :: Python ,
540+ SourceType :: Python ( PySourceType :: Python ) ,
492541 & FormatterSettings :: default ( ) ,
493542 Path :: new ( "test.py" ) ,
494543 FormatBackend :: Uv ,
@@ -529,7 +578,7 @@ def another_function(x,y,z):
529578
530579 let result = format_range (
531580 & document,
532- PySourceType :: Python ,
581+ SourceType :: Python ( PySourceType :: Python ) ,
533582 & FormatterSettings :: default ( ) ,
534583 range,
535584 Path :: new ( "test.py" ) ,
@@ -571,7 +620,7 @@ def hello(very_long_parameter_name_1, very_long_parameter_name_2, very_long_para
571620
572621 let result = format (
573622 & document,
574- PySourceType :: Python ,
623+ SourceType :: Python ( PySourceType :: Python ) ,
575624 & formatter_settings,
576625 Path :: new ( "test.py" ) ,
577626 FormatBackend :: Uv ,
@@ -618,7 +667,7 @@ def hello():
618667
619668 let result = format (
620669 & document,
621- PySourceType :: Python ,
670+ SourceType :: Python ( PySourceType :: Python ) ,
622671 & formatter_settings,
623672 Path :: new ( "test.py" ) ,
624673 FormatBackend :: Uv ,
@@ -650,7 +699,7 @@ def broken(:
650699 // uv should return None for syntax errors (as indicated by the TODO comment)
651700 let result = format (
652701 & document,
653- PySourceType :: Python ,
702+ SourceType :: Python ( PySourceType :: Python ) ,
654703 & FormatterSettings :: default ( ) ,
655704 Path :: new ( "test.py" ) ,
656705 FormatBackend :: Uv ,
@@ -684,7 +733,7 @@ line'''
684733
685734 let result = format (
686735 & document,
687- PySourceType :: Python ,
736+ SourceType :: Python ( PySourceType :: Python ) ,
688737 & formatter_settings,
689738 Path :: new ( "test.py" ) ,
690739 FormatBackend :: Uv ,
@@ -726,7 +775,7 @@ bar = [1, 2, 3,]
726775
727776 let result = format (
728777 & document,
729- PySourceType :: Python ,
778+ SourceType :: Python ( PySourceType :: Python ) ,
730779 & formatter_settings,
731780 Path :: new ( "test.py" ) ,
732781 FormatBackend :: Uv ,
0 commit comments