Example #1
0
        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);
        }
Example #3
0
        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;
        }