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);
}