protected override bool IsDestructiveChangeForSeparator( ISensitiveFragmentSeparatorsInfo separatorInfo, IReadOnlyList <ITextRange> itemsInRange, int start, int oldLength, int newLength, ITextProvider oldText, ITextProvider newText) { var index = GetItemAtPosition(start); if (index >= 0 && newLength > 0 && newText[start + newLength - 1] == '`') { // Typing ` right before the ``` return(true); } index = GetFirstItemBeforePosition(start); if (index >= 0 && Items[index].End == start && newLength > 0 && newText[start] == '`') { // Typing ` right after the ``` return(true); } return(base.IsDestructiveChangeForSeparator(separatorInfo, itemsInRange, start, oldLength, newLength, oldText, newText)); }
private static bool IsADestructiveChangeForSeparator( ISensitiveFragmentSeparatorsInfo separatorInfo, IEnumerable <IArtifact> itemsInRange, int start, int oldLength, int newLength, ITextProvider oldText, ITextProvider newText ) { if (separatorInfo == null || (separatorInfo.LeftSeparator.Length == 0 && separatorInfo.RightSeparator.Length == 0)) { return(false); } // Find out if one of the existing fragments contains position // and if change damages fragment start or end separators string leftSeparator = separatorInfo.LeftSeparator; string rightSeparator = separatorInfo.RightSeparator; var firstTwoItems = itemsInRange.Take(2).ToList(); var item = firstTwoItems.FirstOrDefault(); // If no items are affected, change is unsafe only if new region contains left side separators. if (item == null) { // Simple optimization for whitespace insertion if (oldLength == 0 && string.IsNullOrWhiteSpace(newText.GetText(start, newLength))) { return(false); } // Take into account that user could have deleted space between existing // { and % or added { to the existing % so extend search range accordingly. int fragmentStart = Math.Max(0, start - leftSeparator.Length + 1); int fragmentEnd = Math.Min(newText.Length, start + newLength + leftSeparator.Length - 1); return(newText.IndexOf(leftSeparator, fragmentStart, fragmentEnd - fragmentStart, true) >= 0); } // Is change completely inside an existing item? if (firstTwoItems.Count == 1 && (item.Contains(start) && item.Contains(start + oldLength))) { // Check that change does not affect item left separator if (TextRange.Contains(item.Start, leftSeparator.Length, start)) { return(true); } // Check that change does not affect item right separator. Note that we should not be using // TextRange.Intersect since in case oldLength is zero (like when user is typing right before %} or }}) // TextRange.Intersect will determine that zero-length range intersects with the right separator // which is incorrect. Typing at position 10 does not change separator at position 10. Similarly, // deleting text right before %} or }} does not make change destructive. var htmlToken = item as IHtmlToken; if (htmlToken == null || htmlToken.IsWellFormed) { int rightSeparatorStart = item.End - rightSeparator.Length; if (start + oldLength > rightSeparatorStart) { if (TextRange.Intersect(rightSeparatorStart, rightSeparator.Length, start, oldLength)) { return(true); } } } // Touching left separator is destructive too, like when changing {{ to {{@ // Check that change does not affect item left separator (whitespace is fine) if (item.Start + leftSeparator.Length == start) { if (oldLength == 0) { string text = newText.GetText(start, newLength); if (String.IsNullOrWhiteSpace(text)) { return(false); } } return(true); } int fragmentStart = item.Start + separatorInfo.LeftSeparator.Length; fragmentStart = Math.Max(fragmentStart, start - separatorInfo.RightSeparator.Length + 1); int changeLength = newLength - oldLength; int fragmentEnd = item.End + changeLength; fragmentEnd = Math.Min(fragmentEnd, start + newLength + separatorInfo.RightSeparator.Length - 1); if (newText.IndexOf(separatorInfo.RightSeparator, fragmentStart, fragmentEnd - fragmentStart, true) >= 0) { return(true); } return(false); } return(true); }
protected virtual bool IsDestructiveChangeForSeparator( ISensitiveFragmentSeparatorsInfo separatorInfo, IReadOnlyList <T> itemsInRange, int start, int oldLength, int newLength, ITextProvider oldText, ITextProvider newText) { if (separatorInfo == null) { return(false); } if (separatorInfo.LeftSeparator.Length == 0 && separatorInfo.RightSeparator.Length == 0) { return(false); } // Find out if one of the existing fragments contains position // and if change damages fragment start or end separators var leftSeparator = separatorInfo.LeftSeparator; var rightSeparator = separatorInfo.RightSeparator; // If no items are affected, change is unsafe only if new region contains separators. if (itemsInRange.Count == 0) { // Simple optimization for whitespace insertion if (oldLength == 0 && string.IsNullOrWhiteSpace(newText.GetText(new TextRange(start, newLength)))) { return(false); } // Take into account that user could have deleted space between existing // <! and -- or added - to the existing <!- so extend search range accordingly. var fragmentStart = Math.Max(0, start - leftSeparator.Length + 1); var fragmentEnd = Math.Min(newText.Length, start + newLength + leftSeparator.Length - 1); var fragmentStartPosition = newText.IndexOf(leftSeparator, TextRange.FromBounds(fragmentStart, fragmentEnd), true); if (fragmentStartPosition >= 0) { return(true); } fragmentStart = Math.Max(0, start - rightSeparator.Length + 1); fragmentEnd = Math.Min(newText.Length, start + newLength + rightSeparator.Length - 1); fragmentStartPosition = newText.IndexOf(rightSeparator, TextRange.FromBounds(fragmentStart, fragmentEnd), true); if (fragmentStartPosition >= 0) { return(true); } return(false); } // Is change completely inside an existing item? if (itemsInRange.Count == 1 && (itemsInRange[0].Contains(start) && itemsInRange[0].Contains(start + oldLength))) { // Check that change does not affect item left separator if (TextRange.Contains(itemsInRange[0].Start, leftSeparator.Length, start)) { return(true); } // Check that change does not affect item right separator. Note that we should not be using // TextRange.Intersect since in case oldLength is zero (like when user is typing right before %> or ?>) // TextRange.Intersect will determine that zero-length range intersects with the right separator // which is incorrect. Typing at position 10 does not change separator at position 10. Similarly, // deleting text right before %> or ?> does not make change destructive. var rightSeparatorStart = itemsInRange[0].End - rightSeparator.Length; if (start + oldLength > rightSeparatorStart) { if (TextRange.Intersect(rightSeparatorStart, rightSeparator.Length, start, oldLength)) { return(true); } } // Touching left separator is destructive too, like when changing <% to <%@ // Check that change does not affect item left separator (whitespace is fine) if (itemsInRange[0].Start + leftSeparator.Length == start) { if (oldLength == 0) { var text = newText.GetText(new TextRange(start, newLength)); if (string.IsNullOrWhiteSpace(text)) { return(false); } } return(true); } var fragmentStart = itemsInRange[0].Start + separatorInfo.LeftSeparator.Length; fragmentStart = Math.Max(fragmentStart, start - separatorInfo.RightSeparator.Length + 1); var changeLength = newLength - oldLength; var fragmentEnd = itemsInRange[0].End + changeLength; fragmentEnd = Math.Min(fragmentEnd, start + newLength + separatorInfo.RightSeparator.Length - 1); if (newText.IndexOf(separatorInfo.RightSeparator, TextRange.FromBounds(fragmentStart, fragmentEnd), true) >= 0) { return(true); } return(false); } return(true); }
private bool IsDestructiveChangeForSeparator( ISensitiveFragmentSeparatorsInfo separatorInfo, IEnumerable<IArtifact> itemsInRange, int start, int oldLength, int newLength, ITextProvider oldText, ITextProvider newText ) { if (separatorInfo == null || (separatorInfo.LeftSeparator.Length == 0 && separatorInfo.RightSeparator.Length == 0)) { return false; } // Find out if one of the existing fragments contains position // and if change damages fragment start or end separators string leftSeparator = separatorInfo.LeftSeparator; string rightSeparator = separatorInfo.RightSeparator; var firstTwoItems = itemsInRange.Take(2).ToList(); var item = firstTwoItems.FirstOrDefault(); // If no items are affected, change is unsafe only if new region contains left side separators. if (item == null) { // Simple optimization for whitespace insertion if (oldLength == 0 && string.IsNullOrWhiteSpace(newText.GetText(new TextRange(start, newLength)))) { return false; } // Take into account that user could have deleted space between existing // { and % or added { to the existing % so extend search range accordingly. int fragmentStart = Math.Max(0, start - leftSeparator.Length + 1); int fragmentEnd = Math.Min(newText.Length, start + newLength + leftSeparator.Length - 1); return newText.IndexOf(leftSeparator, TextRange.FromBounds(fragmentStart, fragmentEnd), true) >= 0; } // Is change completely inside an existing item? if (firstTwoItems.Count == 1 && (item.Contains(start) && item.Contains(start + oldLength))) { // Check that change does not affect item left separator if (TextRange.Contains(item.Start, leftSeparator.Length, start)) { return true; } // Check that change does not affect item right separator. Note that we should not be using // TextRange.Intersect since in case oldLength is zero (like when user is typing right before %} or }}) // TextRange.Intersect will determine that zero-length range intersects with the right separator // which is incorrect. Typing at position 10 does not change separator at position 10. Similarly, // deleting text right before %} or }} does not make change destructive. var htmlToken = item as IHtmlToken; if (htmlToken == null || htmlToken.IsWellFormed) { int rightSeparatorStart = item.End - rightSeparator.Length; if (start + oldLength > rightSeparatorStart) { if (TextRange.Intersect(rightSeparatorStart, rightSeparator.Length, start, oldLength)) { return true; } } } // Touching left separator is destructive too, like when changing {{ to {{@ // Check that change does not affect item left separator (whitespace is fine) if (item.Start + leftSeparator.Length == start) { if (oldLength == 0) { string text = newText.GetText(new TextRange(start, newLength)); if (String.IsNullOrWhiteSpace(text)) { return false; } } return true; } int fragmentStart = item.Start + separatorInfo.LeftSeparator.Length; fragmentStart = Math.Max(fragmentStart, start - separatorInfo.RightSeparator.Length + 1); int changeLength = newLength - oldLength; int fragmentEnd = item.End + changeLength; fragmentEnd = Math.Min(fragmentEnd, start + newLength + separatorInfo.RightSeparator.Length - 1); if (newText.IndexOf(separatorInfo.RightSeparator, TextRange.FromBounds(fragmentStart, fragmentEnd), true) >= 0) { return true; } return false; } return true; }