-
Notifications
You must be signed in to change notification settings - Fork 241
Fix formatting of mixed indentation in VS Code #12418
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
0ec302e
1b5312c
632acb8
eaf1e7a
95b7c77
a998769
7de7ca7
4816433
edabdc6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Collections.Immutable; | ||
| using System.Diagnostics; | ||
| using System.Text; | ||
| using Microsoft.AspNetCore.Razor.PooledObjects; | ||
| using Microsoft.CodeAnalysis.Text; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.Razor.TextDifferencing; | ||
|
|
||
| internal partial class SourceTextDiffer | ||
| { | ||
| private sealed class WordDiffer : SourceTextDiffer | ||
| { | ||
| private readonly ImmutableArray<TextSpan> _oldWords; | ||
| private readonly ImmutableArray<TextSpan> _newWords; | ||
|
|
||
| private char[] _oldBuffer; | ||
| private char[] _newBuffer; | ||
| private char[] _appendBuffer; | ||
|
|
||
| protected override int OldSourceLength { get; } | ||
| protected override int NewSourceLength { get; } | ||
|
|
||
| public WordDiffer(SourceText oldText, SourceText newText) : base(oldText, newText) | ||
| { | ||
| _oldBuffer = RentArray(1024); | ||
| _newBuffer = RentArray(1024); | ||
| _appendBuffer = RentArray(1024); | ||
|
|
||
| _oldWords = TokenizeWords(oldText); | ||
| _newWords = TokenizeWords(newText); | ||
|
|
||
| OldSourceLength = _oldWords.Length; | ||
| NewSourceLength = _newWords.Length; | ||
| } | ||
|
|
||
| public override void Dispose() | ||
| { | ||
| ReturnArray(_oldBuffer); | ||
| ReturnArray(_newBuffer); | ||
| ReturnArray(_appendBuffer); | ||
| } | ||
|
|
||
| private static ImmutableArray<TextSpan> TokenizeWords(SourceText text) | ||
| { | ||
| if (text.Length == 0) | ||
| { | ||
| return []; | ||
| } | ||
|
|
||
| using var builder = new PooledArrayBuilder<TextSpan>(); | ||
|
|
||
| var currentSpanStart = 0; | ||
| var currentClassification = Classify(text[0]); | ||
|
|
||
| // This algorithm is simpler than a normal tokenizer might be because we want to keep contiguous | ||
| // whitespace characters in the same "word", and we don't really care about contiguous quotes | ||
| // or slashes, so we can keep it simple and just capture a "word" when the classification of | ||
| // the current character changes. | ||
| var index = 1; | ||
| while (index < text.Length) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| { | ||
| var classification = Classify(text[index]); | ||
| if (classification != currentClassification) | ||
| { | ||
| // We've hit a word boundary, so store this and move on | ||
| builder.Add(TextSpan.FromBounds(currentSpanStart, index)); | ||
| currentSpanStart = index; | ||
| currentClassification = classification; | ||
| } | ||
|
|
||
| index++; | ||
| } | ||
|
|
||
| // It's impossible for the loop to capture the last word | ||
| Debug.Assert(currentSpanStart < text.Length); | ||
| builder.Add(TextSpan.FromBounds(currentSpanStart, text.Length)); | ||
|
|
||
| return builder.ToImmutableAndClear(); | ||
|
|
||
| // The type of classification doesn't matter as long as its unique and equatible | ||
| static int Classify(char c) | ||
| => c switch | ||
| { | ||
| '/' => 0, | ||
| '"' => 1, | ||
| _ when char.IsWhiteSpace(c) => 2, | ||
| _ => 3, | ||
| }; | ||
| } | ||
|
|
||
| protected override bool SourceEqual(int oldSourceIndex, int newSourceIndex) | ||
| { | ||
| var oldWord = _oldWords[oldSourceIndex]; | ||
| var newWord = _newWords[newSourceIndex]; | ||
| if (oldWord.Length != newWord.Length) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| var length = oldWord.Length; | ||
|
|
||
| // Copy the text into char arrays for comparison. Note: To avoid allocation, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this and LineDiffer are very similar other than the creation of the arrays, and the types within, but CharDiffer is quite different. Will move as much down as reasonable.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, this is a bit annoying, and ends up having stuff in the base class that makes no sense to be there. What would be nicer is if both Word and Line differs were both TextSpanDiffers, with different create methods, but I'll do that in a separate PR.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, I take that back, creating TextSpanDiffer is actually pretty simple. |
||
| // we try to reuse the same char buffers and only grow them when a longer | ||
| // line is encountered. | ||
| var oldChars = EnsureBuffer(ref _oldBuffer, oldWord.Length); | ||
| var newChars = EnsureBuffer(ref _newBuffer, newWord.Length); | ||
|
|
||
| OldText.CopyTo(oldWord.Start, oldChars, 0, length); | ||
| NewText.CopyTo(newWord.Start, newChars, 0, length); | ||
|
|
||
| for (var i = 0; i < length; i++) | ||
| { | ||
| if (oldChars[i] != newChars[i]) | ||
| { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| protected override int GetEditPosition(DiffEdit edit) | ||
| => _oldWords[edit.Position].Start; | ||
|
|
||
| protected override int AppendEdit(DiffEdit edit, StringBuilder builder) | ||
| { | ||
| if (edit.Kind == DiffEditKind.Insert) | ||
| { | ||
| Assumes.NotNull(edit.NewTextPosition); | ||
| var newWordIndex = edit.NewTextPosition.GetValueOrDefault(); | ||
|
|
||
| for (var i = 0; i < edit.Length; i++) | ||
| { | ||
| var word = _newWords[newWordIndex + i]; | ||
| var buffer = EnsureBuffer(ref _appendBuffer, word.Length); | ||
| NewText.CopyTo(word.Start, buffer, 0, word.Length); | ||
|
|
||
| builder.Append(buffer, 0, word.Length); | ||
| } | ||
|
|
||
| return _oldWords[edit.Position].Start; | ||
| } | ||
|
|
||
| return _oldWords[edit.Position + edit.Length - 1].End; | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is wonderful!