/// <summary> /// Calculates range that is an intersection of the supplied ranges. /// </summary> /// <returns>Intersection or empty range if ranges don't intersect</returns> public static ITextRange Intersection(ITextRange range1, int rangeStart, int rangeLength) { int start = Math.Max(range1.Start, rangeStart); int end = Math.Min(range1.End, rangeStart + rangeLength); return(start <= end?TextRange.FromBounds(start, end) : TextRange.EmptyRange); }
/// <summary> /// Calculates range that is an intersection of the supplied ranges. /// </summary> /// <returns>Intersection or empty range if ranges don't intersect</returns> public static ITextRange Intersection(ITextRange range1, ITextRange range2) { var start = Math.Max(range1.Start, range2.Start); var end = Math.Min(range1.End, range2.End); return(start <= end?TextRange.FromBounds(start, end) : TextRange.EmptyRange); }
/// <summary> /// Calculates range that includes both supplied ranges. /// </summary> public static ITextRange Union(ITextRange range1, ITextRange range2) { int start = Math.Min(range1.Start, range2.Start); int end = Math.Max(range1.End, range2.End); return(start <= end?TextRange.FromBounds(start, end) : TextRange.EmptyRange); }
private static ITextRange GetCodeBlockRange(ITextSnapshot snapshot, ITextRange block, ITextRange parametersRange) { // In // {r echo=FALSE} // code // // we want to format just *code* section and not spill range into the line // with {r echo=FALSE} or the next (empty) line. I.e. // // {r echo=FALSE} //| code| // // and not // {r echo=FALSE}| // code| //| // var startLine = snapshot.GetLineFromPosition(parametersRange.End); var endline = snapshot.GetLineFromPosition(block.End); if (endline.LineNumber > startLine.LineNumber) { endline = snapshot.GetLineFromLineNumber(endline.LineNumber - 1); } return(TextRange.FromBounds(startLine.EndIncludingLineBreak, endline.End)); }
private void BuildLanguageBlockCollection() { var tokenizer = new MdTokenizer(); var tokens = tokenizer.Tokenize(TextBuffer.CurrentSnapshot.GetText()); var rCodeTokens = tokens.OfType <MarkdownCodeToken>().Where(t => t.LeadingSeparatorLength > 1); // TODO: incremental updates Blocks.Clear(); _separators.Clear(); foreach (var t in rCodeTokens) { // Verify that code block is properly terminated. // If not, it ends at the end of the buffer. _separators.Add(new TextRange(t.Start, t.LeadingSeparatorLength)); // ```{r or `r if (t.IsWellFormed) { // Count backticks Blocks.Add(new RLanguageBlock(TextRange.FromBounds(t.Start + t.LeadingSeparatorLength, t.End - t.TrailingSeparatorLength), t.LeadingSeparatorLength == 2)); _separators.Add(new TextRange(t.End - t.TrailingSeparatorLength, t.TrailingSeparatorLength)); } else { Blocks.Add(new RLanguageBlock(TextRange.FromBounds(t.Start + t.LeadingSeparatorLength, t.End), t.LeadingSeparatorLength == 2)); } } }
public CharacterStream(ITextProvider textProvider, ITextRange range) { _text = textProvider; int end = Math.Min(_text.Length, range.End); _range = TextRange.FromBounds(range.Start, end); Position = _range.Start; _currentChar = _text[_range.Start]; }
public CharacterStream(ITextProvider textProvider, ITextRange range) { Text = textProvider; var end = Math.Min(Text.Length, range.End); _range = TextRange.FromBounds(range.Start, end); Position = _range.Start; CurrentChar = Text.Length > 0 ? Text[_range.Start] : '\0'; }
public static string GetLineLeadingWhitespace(this ITextProvider textProvider, int position) { int start = position; int firstNonWhitespacePosition = position; while (start > 0) { char ch = textProvider[start - 1]; if (ch.IsLineBreak()) { break; } if (!Char.IsWhiteSpace(ch)) { firstNonWhitespacePosition = start - 1; } start -= 1; } return(textProvider.GetText(TextRange.FromBounds(start, firstNonWhitespacePosition))); }
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); }
public IReadOnlyList <T> ItemsInRange(int start) => _collection.ItemsInRange(TextRange.FromBounds(start, start));
/// <summary> /// Compares two collections and calculates 'changed' range. In case this collection /// or comparand are empty, uses lowerBound and upperBound values as range /// delimiters. Typically lowerBound is 0 and upperBound is lentgh of the file. /// </summary> /// <param name="otherCollection">Collection to compare to</param> public virtual ITextRange RangeDifference(IEnumerable <ITextRange> otherCollection, int lowerBound, int upperBound) { if (otherCollection == null) { return(TextRange.FromBounds(lowerBound, upperBound)); } var other = new TextRangeCollection <ITextRange>(otherCollection); if (this.Count == 0 && other.Count == 0) { return(TextRange.EmptyRange); } if (this.Count == 0) { return(TextRange.FromBounds(lowerBound, upperBound)); } if (other.Count == 0) { return(TextRange.FromBounds(lowerBound, upperBound)); } int minCount = Math.Min(this.Count, other.Count); int start = 0; int end = 0; int i, j; for (i = 0; i < minCount; i++) { start = Math.Min(this[i].Start, other[i].Start); if (this[i].Start != other[i].Start || this[i].Length != other[i].Length) { break; } } if (i == minCount) { if (this.Count == other.Count) { return(TextRange.EmptyRange); } if (this.Count > other.Count) { return(TextRange.FromBounds(Math.Min(upperBound, other[minCount - 1].Start), upperBound)); } else { return(TextRange.FromBounds(Math.Min(this[minCount - 1].Start, upperBound), upperBound)); } } for (i = this.Count - 1, j = other.Count - 1; i >= 0 && j >= 0; i--, j--) { end = Math.Max(this[i].End, other[j].End); if (this[i].Start != other[j].Start || this[i].Length != other[j].Length) { break; } } if (start < end) { return(TextRange.FromBounds(start, end)); } return(TextRange.FromBounds(lowerBound, upperBound)); }
public CharacterStream(ITextProvider textProvider) : this(textProvider, TextRange.FromBounds(0, textProvider.Length)) { }