Skip to content

Commit 6b32699

Browse files
authored
Merge pull request #4128 from davidwengier/RevertOnType
2 parents 6e6ad01 + baacd79 commit 6b32699

File tree

3 files changed

+225
-228
lines changed

3 files changed

+225
-228
lines changed

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs

-225
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using System.Collections.Generic;
88
using System.Diagnostics;
99
using System.Linq;
10-
using System.Text;
1110
using System.Threading;
1211
using System.Threading.Tasks;
1312
using Microsoft.AspNetCore.Razor.Language;
@@ -251,230 +250,6 @@ protected async Task<List<TextChange>> AdjustIndentationAsync(FormattingContext
251250
return changes;
252251
}
253252

254-
protected static List<TextChange> CleanupDocument(FormattingContext context, Range? range = null)
255-
{
256-
var isOnType = range is not null;
257-
258-
var text = context.SourceText;
259-
range ??= TextSpan.FromBounds(0, text.Length).AsRange(text);
260-
var csharpDocument = context.CodeDocument.GetCSharpDocument();
261-
262-
var changes = new List<TextChange>();
263-
foreach (var mapping in csharpDocument.SourceMappings)
264-
{
265-
var mappingSpan = new TextSpan(mapping.OriginalSpan.AbsoluteIndex, mapping.OriginalSpan.Length);
266-
var mappingRange = mappingSpan.AsRange(text);
267-
if (!range.LineOverlapsWith(mappingRange))
268-
{
269-
// We don't care about this range. It didn't change.
270-
continue;
271-
}
272-
273-
CleanupSourceMappingStart(context, mappingRange, changes, isOnType, out var newLineAdded);
274-
275-
CleanupSourceMappingEnd(context, mappingRange, changes, newLineAdded);
276-
}
277-
278-
return changes;
279-
}
280-
281-
private static void CleanupSourceMappingStart(FormattingContext context, Range sourceMappingRange, List<TextChange> changes, bool isOnType, out bool newLineAdded)
282-
{
283-
newLineAdded = false;
284-
285-
//
286-
// We look through every source mapping that intersects with the affected range and
287-
// bring the first line to its own line and adjust its indentation,
288-
//
289-
// E.g,
290-
//
291-
// @{ public int x = 0;
292-
// }
293-
//
294-
// becomes,
295-
//
296-
// @{
297-
// public int x = 0;
298-
// }
299-
//
300-
301-
var text = context.SourceText;
302-
var sourceMappingSpan = sourceMappingRange.AsTextSpan(text);
303-
if (!ShouldFormat(context, sourceMappingSpan, allowImplicitStatements: false))
304-
{
305-
// We don't want to run cleanup on this range.
306-
return;
307-
}
308-
309-
if (sourceMappingRange.Start.Character == 0)
310-
{
311-
// It already starts on a fresh new line which doesn't need cleanup.
312-
// E.g, (The mapping starts at | in the below case)
313-
// @{
314-
// @: Some html
315-
// | var x = 123;
316-
// }
317-
//
318-
319-
return;
320-
}
321-
322-
// @{
323-
// if (true)
324-
// {
325-
// <div></div>|
326-
//
327-
// |}
328-
// }
329-
// We want to return the length of the range marked by |...|
330-
//
331-
var whitespaceLength = text.GetFirstNonWhitespaceOffset(sourceMappingSpan, out var newLineCount);
332-
if (whitespaceLength == null)
333-
{
334-
// There was no content after the start of this mapping. Meaning it already is clean.
335-
// E.g,
336-
// @{|
337-
// ...
338-
// }
339-
340-
return;
341-
}
342-
343-
var spanToReplace = new TextSpan(sourceMappingSpan.Start, whitespaceLength.Value);
344-
if (!context.TryGetIndentationLevel(spanToReplace.End, out var contentIndentLevel))
345-
{
346-
// Can't find the correct indentation for this content. Leave it alone.
347-
return;
348-
}
349-
350-
if (newLineCount == 0)
351-
{
352-
// If on type formatting is happening on a single line then we just clean up the start to one space
353-
// so @{ throw null; } will be formatted to @{ throw null; }
354-
// Ideally we'd put that across three lines, which is what normal formatting does, but since we
355-
// can't control the cursor, that doesn't end well.
356-
if (isOnType && sourceMappingRange.Start.Line == sourceMappingRange.End.Line)
357-
{
358-
changes.Add(new TextChange(spanToReplace, " "));
359-
return;
360-
}
361-
362-
newLineAdded = true;
363-
newLineCount = 1;
364-
}
365-
366-
// At this point, `contentIndentLevel` should contain the correct indentation level for `}` in the above example.
367-
// Make sure to preserve the same number of blank lines as the original string had
368-
var replacement = PrependLines(context.GetIndentationLevelString(contentIndentLevel), context.NewLineString, newLineCount);
369-
370-
// After the below change the above example should look like,
371-
// @{
372-
// if (true)
373-
// {
374-
// <div></div>
375-
// }
376-
// }
377-
var change = new TextChange(spanToReplace, replacement);
378-
changes.Add(change);
379-
}
380-
381-
private static string PrependLines(string text, string newLine, int count)
382-
{
383-
var builder = new StringBuilder((newLine.Length * count) + text.Length);
384-
for (var i = 0; i < count; i++)
385-
{
386-
builder.Append(newLine);
387-
}
388-
389-
builder.Append(text);
390-
return builder.ToString();
391-
}
392-
393-
private static void CleanupSourceMappingEnd(FormattingContext context, Range sourceMappingRange, List<TextChange> changes, bool newLineWasAddedAtStart)
394-
{
395-
//
396-
// We look through every source mapping that intersects with the affected range and
397-
// bring the content after the last line to its own line and adjust its indentation,
398-
//
399-
// E.g,
400-
//
401-
// @{
402-
// if (true)
403-
// { <div></div>
404-
// }
405-
// }
406-
//
407-
// becomes,
408-
//
409-
// @{
410-
// if (true)
411-
// {
412-
// </div></div>
413-
// }
414-
// }
415-
//
416-
417-
var text = context.SourceText;
418-
var sourceMappingSpan = sourceMappingRange.AsTextSpan(text);
419-
var mappingEndLineIndex = sourceMappingRange.End.Line;
420-
421-
var startsInCSharpContext = context.Indentations[mappingEndLineIndex].StartsInCSharpContext;
422-
423-
// If the span is on a single line, and we added a line, then end point is now on a line that does start in a C# context.
424-
if (!startsInCSharpContext && newLineWasAddedAtStart && sourceMappingRange.Start.Line == mappingEndLineIndex)
425-
{
426-
startsInCSharpContext = true;
427-
}
428-
429-
if (!startsInCSharpContext)
430-
{
431-
// For corner cases like (Position marked with |),
432-
// It is already in a separate line. It doesn't need cleaning up.
433-
// @{
434-
// if (true}
435-
// {
436-
// |<div></div>
437-
// }
438-
// }
439-
//
440-
return;
441-
}
442-
443-
var endSpan = TextSpan.FromBounds(sourceMappingSpan.End, sourceMappingSpan.End);
444-
if (!ShouldFormat(context, endSpan, allowImplicitStatements: false))
445-
{
446-
// We don't want to run cleanup on this range.
447-
return;
448-
}
449-
450-
var contentStartOffset = text.Lines[mappingEndLineIndex].GetFirstNonWhitespaceOffset(sourceMappingRange.End.Character);
451-
if (contentStartOffset == null)
452-
{
453-
// There is no content after the end of this source mapping. No need to clean up.
454-
return;
455-
}
456-
457-
var spanToReplace = new TextSpan(sourceMappingSpan.End, 0);
458-
if (!context.TryGetIndentationLevel(spanToReplace.End, out var contentIndentLevel))
459-
{
460-
// Can't find the correct indentation for this content. Leave it alone.
461-
return;
462-
}
463-
464-
// At this point, `contentIndentLevel` should contain the correct indentation level for `}` in the above example.
465-
var replacement = context.NewLineString + context.GetIndentationLevelString(contentIndentLevel);
466-
467-
// After the below change the above example should look like,
468-
// @{
469-
// if (true)
470-
// {
471-
// <div></div>
472-
// }
473-
// }
474-
var change = new TextChange(spanToReplace, replacement);
475-
changes.Add(change);
476-
}
477-
478253
protected static bool ShouldFormat(FormattingContext context, TextSpan mappingSpan, bool allowImplicitStatements)
479254
{
480255
// We should be called with the range of various C# SourceMappings.

0 commit comments

Comments
 (0)