11use crate :: edit:: { Replacement , ToRangeExt } ;
2+ use crate :: fix:: Fixes ;
23use crate :: server:: api:: LSPResult ;
34use crate :: server:: { client:: Notifier , Result } ;
45use crate :: session:: DocumentSnapshot ;
6+ use crate :: { PositionEncoding , TextDocument } ;
57use lsp_types:: { self as types, request as req} ;
8+ use ruff_python_ast:: PySourceType ;
69use ruff_source_file:: LineIndex ;
10+ use ruff_workspace:: FormatterSettings ;
711use types:: TextEdit ;
812
913pub ( crate ) struct Format ;
@@ -23,25 +27,73 @@ impl super::BackgroundDocumentRequestHandler for Format {
2327 }
2428}
2529
30+ /// Formats either a full text document or each individual cell in a single notebook document.
31+ pub ( super ) fn format_full_document ( snapshot : & DocumentSnapshot ) -> Result < Fixes > {
32+ let mut fixes = Fixes :: default ( ) ;
33+
34+ if let Some ( notebook) = snapshot. query ( ) . as_notebook ( ) {
35+ for ( url, text_document) in notebook
36+ . urls ( )
37+ . map ( |url| ( url. clone ( ) , notebook. cell_document_by_uri ( url) . unwrap ( ) ) )
38+ {
39+ if let Some ( changes) = format_text_document (
40+ text_document,
41+ snapshot. query ( ) . source_type ( ) ,
42+ snapshot. query ( ) . settings ( ) . formatter ( ) ,
43+ snapshot. encoding ( ) ,
44+ true ,
45+ ) ? {
46+ fixes. insert ( url, changes) ;
47+ }
48+ }
49+ } else {
50+ if let Some ( changes) = format_text_document (
51+ snapshot. query ( ) . as_single_document ( ) . unwrap ( ) ,
52+ snapshot. query ( ) . source_type ( ) ,
53+ snapshot. query ( ) . settings ( ) . formatter ( ) ,
54+ snapshot. encoding ( ) ,
55+ false ,
56+ ) ? {
57+ fixes. insert ( snapshot. query ( ) . make_key ( ) . into_url ( ) , changes) ;
58+ }
59+ }
60+
61+ Ok ( fixes)
62+ }
63+
64+ /// Formats either a full text document or an specific notebook cell. If the query within the snapshot is a notebook document
65+ /// with no selected cell, this will throw an error.
2666pub ( super ) fn format_document ( snapshot : & DocumentSnapshot ) -> Result < super :: FormatResponse > {
27- let doc = snapshot
67+ let text_document = snapshot
2868 . query ( )
2969 . as_single_document ( )
3070 . expect ( "format should only be called on text documents or notebook cells" ) ;
31- let source = doc. contents ( ) ;
32- let mut formatted = crate :: format:: format (
33- doc,
71+ format_text_document (
72+ text_document,
3473 snapshot. query ( ) . source_type ( ) ,
3574 snapshot. query ( ) . settings ( ) . formatter ( ) ,
75+ snapshot. encoding ( ) ,
76+ snapshot. query ( ) . as_notebook ( ) . is_some ( ) ,
3677 )
37- . with_failure_code ( lsp_server:: ErrorCode :: InternalError ) ?;
78+ }
79+
80+ fn format_text_document (
81+ text_document : & TextDocument ,
82+ source_type : PySourceType ,
83+ formatter_settings : & FormatterSettings ,
84+ encoding : PositionEncoding ,
85+ is_notebook : bool ,
86+ ) -> Result < super :: FormatResponse > {
87+ let source = text_document. contents ( ) ;
88+ let mut formatted = crate :: format:: format ( text_document, source_type, formatter_settings)
89+ . with_failure_code ( lsp_server:: ErrorCode :: InternalError ) ?;
3890 // fast path - if the code is the same, return early
3991 if formatted == source {
4092 return Ok ( None ) ;
4193 }
4294
4395 // special case - avoid adding a newline to a notebook cell if it didn't already exist
44- if snapshot . query ( ) . as_notebook ( ) . is_some ( ) {
96+ if is_notebook {
4597 let mut trimmed = formatted. as_str ( ) ;
4698 if !source. ends_with ( "\r \n " ) {
4799 trimmed = trimmed. trim_end_matches ( "\r \n " ) ;
@@ -57,7 +109,7 @@ pub(super) fn format_document(snapshot: &DocumentSnapshot) -> Result<super::Form
57109
58110 let formatted_index: LineIndex = LineIndex :: from_source_text ( & formatted) ;
59111
60- let unformatted_index = doc . index ( ) ;
112+ let unformatted_index = text_document . index ( ) ;
61113
62114 let Replacement {
63115 source_range,
@@ -70,7 +122,7 @@ pub(super) fn format_document(snapshot: &DocumentSnapshot) -> Result<super::Form
70122 ) ;
71123
72124 Ok ( Some ( vec ! [ TextEdit {
73- range: source_range. to_range( source, unformatted_index, snapshot . encoding( ) ) ,
125+ range: source_range. to_range( source, unformatted_index, encoding) ,
74126 new_text: formatted[ formatted_range] . to_owned( ) ,
75127 } ] ) )
76128}
0 commit comments