@@ -2221,3 +2221,164 @@ func (f *FourslashTest) verifyBaselines(t *testing.T) {
22212221}
22222222
22232223var AnyTextEdits * []* lsproto.TextEdit
2224+
2225+ // VerifyFormatDocument verifies formatting of the entire document.
2226+ // It sends a textDocument/formatting request and compares the result with a baseline.
2227+ func (f * FourslashTest ) VerifyFormatDocument (t * testing.T , options * lsproto.FormattingOptions ) {
2228+ if options == nil {
2229+ options = & lsproto.FormattingOptions {
2230+ TabSize : 4 ,
2231+ InsertSpaces : true ,
2232+ }
2233+ }
2234+
2235+ params := & lsproto.DocumentFormattingParams {
2236+ TextDocument : lsproto.TextDocumentIdentifier {
2237+ Uri : lsconv .FileNameToDocumentURI (f .activeFilename ),
2238+ },
2239+ Options : options ,
2240+ }
2241+
2242+ resMsg , result , resultOk := sendRequest (t , f , lsproto .TextDocumentFormattingInfo , params )
2243+ if resMsg == nil {
2244+ t .Fatal ("Nil response received for document formatting request" )
2245+ }
2246+ if ! resultOk {
2247+ t .Fatalf ("Unexpected response type for document formatting request: %T" , resMsg .AsResponse ().Result )
2248+ }
2249+
2250+ f .addFormattingResultToBaseline (t , "formatDocument" , result .TextEdits )
2251+ }
2252+
2253+ // VerifyFormatSelection verifies formatting of a selected range.
2254+ // It sends a textDocument/rangeFormatting request and compares the result with a baseline.
2255+ func (f * FourslashTest ) VerifyFormatSelection (t * testing.T , markerOrRange MarkerOrRange , options * lsproto.FormattingOptions ) {
2256+ if options == nil {
2257+ options = & lsproto.FormattingOptions {
2258+ TabSize : 4 ,
2259+ InsertSpaces : true ,
2260+ }
2261+ }
2262+
2263+ f .goToMarker (t , markerOrRange )
2264+ var formatRange lsproto.Range
2265+ if rangeMarker , ok := markerOrRange .(* RangeMarker ); ok {
2266+ formatRange = rangeMarker .LSRange
2267+ } else {
2268+ // If it's just a marker position, format from that position to the end of the line
2269+ formatRange = lsproto.Range {
2270+ Start : f .currentCaretPosition ,
2271+ End : f .currentCaretPosition ,
2272+ }
2273+ }
2274+
2275+ params := & lsproto.DocumentRangeFormattingParams {
2276+ TextDocument : lsproto.TextDocumentIdentifier {
2277+ Uri : lsconv .FileNameToDocumentURI (f .activeFilename ),
2278+ },
2279+ Range : formatRange ,
2280+ Options : options ,
2281+ }
2282+
2283+ resMsg , result , resultOk := sendRequest (t , f , lsproto .TextDocumentRangeFormattingInfo , params )
2284+ if resMsg == nil {
2285+ t .Fatal ("Nil response received for range formatting request" )
2286+ }
2287+ if ! resultOk {
2288+ t .Fatalf ("Unexpected response type for range formatting request: %T" , resMsg .AsResponse ().Result )
2289+ }
2290+
2291+ f .addFormattingResultToBaseline (t , "formatSelection" , result .TextEdits )
2292+ }
2293+
2294+ // VerifyFormatOnType verifies on-type formatting (e.g., after typing `;`, `}`, or newline).
2295+ // It sends a textDocument/onTypeFormatting request and compares the result with a baseline.
2296+ func (f * FourslashTest ) VerifyFormatOnType (t * testing.T , marker string , character string , options * lsproto.FormattingOptions ) {
2297+ if options == nil {
2298+ options = & lsproto.FormattingOptions {
2299+ TabSize : 4 ,
2300+ InsertSpaces : true ,
2301+ }
2302+ }
2303+
2304+ f .GoToMarker (t , marker )
2305+
2306+ params := & lsproto.DocumentOnTypeFormattingParams {
2307+ TextDocument : lsproto.TextDocumentIdentifier {
2308+ Uri : lsconv .FileNameToDocumentURI (f .activeFilename ),
2309+ },
2310+ Position : f .currentCaretPosition ,
2311+ Ch : character ,
2312+ Options : options ,
2313+ }
2314+
2315+ resMsg , result , resultOk := sendRequest (t , f , lsproto .TextDocumentOnTypeFormattingInfo , params )
2316+ if resMsg == nil {
2317+ t .Fatal ("Nil response received for on-type formatting request" )
2318+ }
2319+ if ! resultOk {
2320+ // Check if result is nil - this is valid, just means no formatting needed
2321+ resp := resMsg .AsResponse ()
2322+ if resp .Result == nil {
2323+ // No formatting edits needed
2324+ f .addFormattingResultToBaseline (t , "formatOnType" , nil )
2325+ return
2326+ }
2327+ t .Fatalf ("Unexpected response type for on-type formatting request: %T" , resp .Result )
2328+ }
2329+
2330+ f .addFormattingResultToBaseline (t , "formatOnType" , result .TextEdits )
2331+ }
2332+
2333+ // addFormattingResultToBaseline adds formatting results to the baseline.
2334+ // It shows the original file content and the formatted content side by side.
2335+ func (f * FourslashTest ) addFormattingResultToBaseline (t * testing.T , command string , edits * []* lsproto.TextEdit ) {
2336+ script := f .getScriptInfo (f .activeFilename )
2337+ originalContent := script .content
2338+
2339+ var formattedContent string
2340+ if edits == nil || len (* edits ) == 0 {
2341+ formattedContent = originalContent
2342+ } else {
2343+ // Apply edits to get formatted content
2344+ formattedContent = f .applyEditsToString (originalContent , * edits )
2345+ }
2346+
2347+ var result strings.Builder
2348+ result .WriteString (fmt .Sprintf ("// Original (%s):\n " , f .activeFilename ))
2349+ for _ , line := range strings .Split (originalContent , "\n " ) {
2350+ result .WriteString ("// " + line + "\n " )
2351+ }
2352+ result .WriteString ("\n " )
2353+ result .WriteString ("// Formatted:\n " )
2354+ for _ , line := range strings .Split (formattedContent , "\n " ) {
2355+ result .WriteString ("// " + line + "\n " )
2356+ }
2357+
2358+ f .addResultToBaseline (t , command , result .String ())
2359+ }
2360+
2361+ // applyEditsToString applies text edits to a string and returns the result.
2362+ func (f * FourslashTest ) applyEditsToString (content string , edits []* lsproto.TextEdit ) string {
2363+ script := newScriptInfo (f .activeFilename , content )
2364+ converters := lsconv .NewConverters (lsproto .PositionEncodingKindUTF8 , func (_ string ) * lsconv.LSPLineMap {
2365+ return script .lineMap
2366+ })
2367+
2368+ // Sort edits in reverse order to avoid affecting positions
2369+ sortedEdits := slices .Clone (edits )
2370+ slices .SortFunc (sortedEdits , func (a , b * lsproto.TextEdit ) int {
2371+ aStart := converters .LineAndCharacterToPosition (script , a .Range .Start )
2372+ bStart := converters .LineAndCharacterToPosition (script , b .Range .Start )
2373+ return int (bStart ) - int (aStart )
2374+ })
2375+
2376+ result := content
2377+ for _ , edit := range sortedEdits {
2378+ start := int (converters .LineAndCharacterToPosition (script , edit .Range .Start ))
2379+ end := int (converters .LineAndCharacterToPosition (script , edit .Range .End ))
2380+ result = result [:start ] + edit .NewText + result [end :]
2381+ }
2382+
2383+ return result
2384+ }
0 commit comments