IEnumerable<ITextSnapshotLine> GetLinesToAlign(ITextSnapshot snapshot) { int start = snapshot.GetLineNumberFromPosition(m_view.Selection.Start.Position); int end = snapshot.GetLineNumberFromPosition(m_view.Selection.End.Position); if (start == end) { start = 0; end = snapshot.LineCount -1; } return start.UpTo(end).Select(x => snapshot.GetLineFromLineNumber(x)); }
/// <summary> /// Determines if range is large enough to be outlined /// </summary> private static bool OutlineRange(ITextSnapshot snapshot, ITextRange range, out int startLineNumber, out int endLineNumber) { int start = Math.Max(0, range.Start); int end = Math.Min(range.End, snapshot.Length); startLineNumber = endLineNumber = 0; if (start < end) { startLineNumber = snapshot.GetLineNumberFromPosition(start); endLineNumber = snapshot.GetLineNumberFromPosition(end); return(endLineNumber - startLineNumber + 1 >= _minLinesToOutline); } return(false); }
protected override TeXCommentAdornment CreateAdornment(TeXCommentTag dataTag, ITextSnapshot snapshot) { var lineSpan = new LineSpan( snapshot.GetLineNumberFromPosition(dataTag.TeXBlock.Span.Start), snapshot.GetLineNumberFromPosition(dataTag.TeXBlock.Span.End)); var lastLine = snapshot.GetLineFromLineNumber(lineSpan.LastLine); var lastLineWidthWithoutStartWhiteSpaces = (lastLine.Extent.Length - dataTag.TeXBlock.LastLineWhiteSpacesAtStart) * TextView.FormattedLineSource?.ColumnWidth; var adornment = new TeXCommentAdornment( TextView, dataTag, lineSpan, lastLineWidthWithoutStartWhiteSpaces ?? 0, textHasBeenEdited ? TeXCommentAdornmentState.EditingAndRenderingPreview : TeXCommentAdornmentState.Rendering, span => { //var blockSpans = texCommentBlocks.GetBlockSpansWithLastLineBreakIntersectedBy(Snapshot, span); //foreach (var blockSpan in blockSpans) //{ // RaiseTagsChanged(new SnapshotSpan(Snapshot, blockSpan)); //} //RaiseTagsChanged(new SnapshotSpan(Snapshot, 0, Snapshot.Length)); InvalidateSpans(new List <SnapshotSpan>() { new SnapshotSpan(Snapshot, 0, Snapshot.Length) }); }, isInEditMode => { ForAllCurrentlyUsedAdornments(a => a.CurrentState = isInEditMode ? TeXCommentAdornmentState.EditingAndRenderingPreview : TeXCommentAdornmentState.Rendering, false); }, (tag, attributeText) => { var pos = tag.Span.Start + tag.TeXBlock.FirstLineWhiteSpacesAtStart + tag.TeXBlock.TeXCommentPrefix.Length + tag.TeXBlock.PropertiesSegmentLength; Snapshot.TextBuffer.Insert(pos, $"[{attributeText}]"); }, renderingManager, vsSettings); TextView.TextBuffer.Changed += adornment.HandleTextBufferChanged; MarkAdornmentLines(lineSpan, adornment); return(adornment); }
private static int DetermineIndentationColumn( IEditorOptions editorOptions, IEnumerable <SnapshotSpan> spans) { int?indentationColumn = null; foreach (SnapshotSpan span in spans) { ITextSnapshot snapshot = span.Snapshot; int startLineNumber = snapshot.GetLineNumberFromPosition(span.Start); int endLineNumber = snapshot.GetLineNumberFromPosition(span.End); // If the span starts after the first non-whitespace of the first line, we'll // exclude that line to avoid throwing off the calculation. Otherwise, the // incorrect indentation will be returned for lambda cases like so: // // void M() // { // Func<int> f = () => // { // return 1; // }; // } // // Without throwing out the first line in the example above, the indentation column // used will be 4, rather than 8. int?startLineFirstNonWhitespace = snapshot.GetLineFromLineNumber(startLineNumber).GetFirstNonWhitespacePosition(); if (startLineFirstNonWhitespace.HasValue && startLineFirstNonWhitespace.Value < span.Start) { startLineNumber++; } for (int lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) { ITextSnapshotLine line = snapshot.GetLineFromLineNumber(lineNumber); if (string.IsNullOrWhiteSpace(line.GetText())) { continue; } indentationColumn = indentationColumn.HasValue ? Math.Min(indentationColumn.Value, line.GetText().GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(editorOptions.GetTabSize())) : line.GetText().GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(editorOptions.GetTabSize()); } } return(indentationColumn ?? 0); }
/// <summary> /// Gets the number of tabs from the beginning of the line. /// </summary> /// <param name="lastSlashPosition"></param> /// <param name="capture">The snapshot to use as the context of the line.</param> /// <returns></returns> public static string GetIndention(int lastSlashPosition, ITextSnapshot capture, bool isAboveFunction = false) { int lineNum = capture.GetLineNumberFromPosition(lastSlashPosition); if (isAboveFunction) { lineNum++; } else { lineNum--; } lineNum = GetFunctionDeclarationLineNumber(capture, lineNum, isAboveFunction); string space = capture.GetLineFromLineNumber(lineNum).GetText(); int leadingSpace = space.Length - space.TrimStart().Length; space = space.Substring(0, leadingSpace); if (isAboveFunction) { return(space); } return(space + GetTab()); }
private void FormatLine() { ITextSnapshot snapshot = this.wpfTextView.TextSnapshot; if (snapshot != snapshot.TextBuffer.CurrentSnapshot) { return; } using (ITextEdit edit = this.wpfTextView.TextBuffer.CreateEdit()) { var lineNum = snapshot.GetLineNumberFromPosition(this.wpfTextView.Caret.Position.BufferPosition); if (lineNum > 0) { var line = snapshot.GetLineFromLineNumber(lineNum - 1); if (!edit.Replace(new Span(line.Start, line.End - line.Start), FormatLine(new Tokenizer(), line.GetText()))) { return; } edit.Apply(); } } }
private void TokenFromPosition(ITextSnapshot snapshot, int position, out int itemIndex, out int offset) { // Normally token stream does not change after formatting so we can simply rely on the fact // that caret position is going to remain relative to the same token index itemIndex = -1; offset = 0; // Expand range to include the next line. This is needed when user introduces line break. var lineNumber = snapshot.GetLineNumberFromPosition(_changingRange.End); if (lineNumber < snapshot.LineCount - 1) { var end = snapshot.GetLineFromLineNumber(lineNumber + 1).End; _changingRange = TextRange.FromBounds(_changingRange.Start, end); } var tokenizer = new RTokenizer(); IReadOnlyTextRangeCollection <RToken> tokens = tokenizer.Tokenize(new TextProvider(snapshot), _changingRange.Start, _changingRange.Length, true); // Check if position is adjacent to previous token int prevItemIndex = tokens.GetFirstItemBeforePosition(position); if (prevItemIndex >= 0 && tokens[prevItemIndex].End == position) { itemIndex = prevItemIndex; offset = -tokens[itemIndex].Length; return; } int nextItemIndex = tokens.GetFirstItemAfterOrAtPosition(position); if (nextItemIndex >= 0) { // If two tokens are adjacent, gravity is negative, i.e. caret travels // with preceding token so it won't just to aniother line if, say, // formatter decides to insert a new line between tokens. if (nextItemIndex > 0 && tokens[nextItemIndex - 1].End == tokens[nextItemIndex].Start) { nextItemIndex--; } offset = tokens[nextItemIndex].Start - position; itemIndex = nextItemIndex; return; } // We are past last token if (tokens.Count > 0) { itemIndex = tokens.Count - 1; offset = tokens[itemIndex].Start - position; } else { itemIndex = -1; offset = position; } }
private static void IndentCaretInNewScope(ITextView textView, IScope scope, SnapshotPoint caretBufferPoint, RFormatOptions options) { if (scope == null || scope.OpenCurlyBrace == null) { return; } ITextSnapshot rSnapshot = caretBufferPoint.Snapshot; ITextBuffer rTextBuffer = rSnapshot.TextBuffer; int rCaretPosition = caretBufferPoint.Position; var caretLine = rSnapshot.GetLineFromPosition(rCaretPosition); int innerIndentSize = SmartIndenter.InnerIndentSizeFromNode(rTextBuffer, scope, options); int openBraceLineNumber = rSnapshot.GetLineNumberFromPosition(scope.OpenCurlyBrace.Start); var braceLine = rSnapshot.GetLineFromLineNumber(openBraceLineNumber); var indentLine = rSnapshot.GetLineFromLineNumber(openBraceLineNumber + 1); string lineBreakText = braceLine.GetLineBreakText(); rTextBuffer.Insert(indentLine.Start, lineBreakText); // Fetch the line again since snapshot has changed when line break was inserted indentLine = rTextBuffer.CurrentSnapshot.GetLineFromLineNumber(openBraceLineNumber + 1); // Map new caret position back to the view var positionInView = textView.MapUpToView(indentLine.Start); if (positionInView.HasValue) { var viewIndentLine = textView.TextBuffer.CurrentSnapshot.GetLineFromPosition(positionInView.Value); textView.Caret.MoveTo(new VirtualSnapshotPoint(viewIndentLine.Start, innerIndentSize)); } }
private IEnumerable <ITagSpan <IOutliningRegionTag> > ProcessHeadingBlocks(IEnumerable <MarkdownObject> descendants, ITextSnapshot snapshot) { var headingBlocks = descendants.OfType <HeadingBlock>(); foreach (var block in headingBlocks) { var next = headingBlocks.FirstOrDefault(h => h.Level <= block.Level && h.Line > block.Line); // Treat Setext Heading or ATX Heading uniformly var lineNumber = (next != null ? snapshot.GetLineNumberFromPosition(next.Span.Start) : snapshot.LineCount) - 1; var length = GetSectionEnding(snapshot.GetLineFromLineNumber(lineNumber)) - block.Span.Start; if (snapshot.Length >= block.Span.Start + block.Span.Length) { string text = snapshot.GetText(block.ToSimpleSpan()); var span = new SnapshotSpan(snapshot, block.Span.Start, length); var spanText = span.GetText(); if (spanText.Contains('\r') || spanText.Contains('\n')) { yield return(CreateTag(span, text, spanText)); } } } }
public T GetState(ITextSnapshot snapshot, int startPosition) { int numberFromPosition = snapshot.GetLineNumberFromPosition(startPosition); if (numberFromPosition == 0) { return(default(T)); } int val2 = numberFromPosition - 1; if (this._states[val2].HasValue) { return(this._states[val2].Value); } int endLine = val2; do { ; }while (val2-- > 0 && !this._states[val2].HasValue); T state = val2 < 0 ? default(T) : this._states[val2].Value; this.CacheLineStates(snapshot, Math.Max(0, val2), endLine, state); return(this._states[endLine].Value); }
private static TagSpan GetOutlineSpan(ITextSnapshot snapshot, IOutlinableResult outlineResult) { TagSpan tagSpan = null; try { int length = outlineResult.EndIndex - outlineResult.StartIndex; if (length > 0) { var headerLength = outlineResult.DecoratorEnd - outlineResult.DecoratorStart; ITextSnapshotLine startLine; if ((startLine = snapshot.GetLineFromPosition(outlineResult.DecoratorStart)).LineNumber != snapshot.GetLineNumberFromPosition(outlineResult.DecoratorEnd)) { // the decorator range spans multiple lines, so we want to truncate that headerLength = startLine.End.Position - outlineResult.DecoratorStart; } Span headerSpan = new Span(outlineResult.DecoratorStart, headerLength); var span = GetFinalSpan(snapshot, outlineResult.StartIndex, length); tagSpan = new TagSpan( new SnapshotSpan(snapshot, span), new OutliningTag(snapshot, headerSpan, span, true) ); } } catch (ArgumentException) { // sometimes Python's parser gives us bad spans, ignore those and fix the parser Debug.Assert(false, "bad argument when making span/tag"); } return(tagSpan); }
/// <summary> /// Gets the caret column position when moving caret vertically. /// If the Caret is already on first or last line the caret is set /// to the start of file or to the end of the file, respectively. /// If the Caret is positioned left off the stored column position /// the caret is set to the stored column position or the end of line. /// </summary> /// <param name="caretPosition"></param> /// <param name="snapshot"></param> /// <returns></returns> internal int GetCaretColumnPosition(int caretPosition, ITextSnapshot snapshot) { var previousLineNumber = snapshot.GetLineNumberFromPosition(Caret.GetPosition(snapshot)); var caretLine = snapshot.GetLineFromPosition(caretPosition); if (caretLine.LineNumber == previousLineNumber && caretLine.LineNumber == 0) { return(0); } else if (caretLine.LineNumber == previousLineNumber && caretLine.LineNumber == snapshot.LineCount - 1) { return(snapshot.Length); } else if (ColumnPosition > (caretPosition - caretLine.Start.Position)) { var correctColumnPosition = (ColumnPosition > caretLine.Length) ? caretLine.Length : ColumnPosition; return(caretLine.Start.Position + correctColumnPosition); } else { return(caretPosition); } }
private static void IndentCaretInNewScope(ITextView textView, ITextBuffer textBuffer, IScope scope, RFormatOptions options) { ITextSnapshot snapshot = textBuffer.CurrentSnapshot; SnapshotPoint?positionInBuffer = textView.MapDownToBuffer(textView.Caret.Position.BufferPosition, textBuffer); if (!positionInBuffer.HasValue || scope == null || scope.OpenCurlyBrace == null) { return; } int position = positionInBuffer.Value.Position; ITextSnapshotLine caretLine = snapshot.GetLineFromPosition(position); int innerIndentSize = SmartIndenter.InnerIndentSizeFromNode(textBuffer, scope, options); int openBraceLineNumber = snapshot.GetLineNumberFromPosition(scope.OpenCurlyBrace.Start); ITextSnapshotLine braceLine = snapshot.GetLineFromLineNumber(openBraceLineNumber); ITextSnapshotLine indentLine = snapshot.GetLineFromLineNumber(openBraceLineNumber + 1); string lineBreakText = braceLine.GetLineBreakText(); textBuffer.Insert(indentLine.Start, lineBreakText); positionInBuffer = textView.MapUpToBuffer(indentLine.Start.Position, textView.TextBuffer); if (!positionInBuffer.HasValue) { return; } indentLine = textView.TextBuffer.CurrentSnapshot.GetLineFromPosition(positionInBuffer.Value); textView.Caret.MoveTo(new VirtualSnapshotPoint(indentLine, innerIndentSize)); }
internal static SnapshotPoint GetSnapshotPositionFromProtocolPosition(this ITextSnapshot textSnapshot, Position position) { var line = textSnapshot.GetLineNumberFromPosition(position.Line); var snapshotPosition = textSnapshot.GetLineFromLineNumber(position.Line).Start + position.Character; return(new SnapshotPoint(textSnapshot, snapshotPosition)); }
private void OutlineBlock(IToken startToken, IToken stopToken, object collapsedForm) { Span span = new Span(startToken.StartIndex, stopToken.StopIndex - startToken.StartIndex + 1); // don't collapse blocks that don't span multiple lines if (_snapshot.GetLineNumberFromPosition(span.Start) == _snapshot.GetLineNumberFromPosition(span.End)) { return; } SnapshotSpan snapshotSpan = new SnapshotSpan(_snapshot, span); IOutliningRegionTag tag = new OutliningRegionTag(false, false, collapsedForm, snapshotSpan.GetText()); TagSpan <IOutliningRegionTag> tagSpan = new TagSpan <IOutliningRegionTag>(snapshotSpan, tag); _outliningRegions.Add(tagSpan); }
protected override void UpdateAdornment(TeXCommentAdornment adornment, TeXCommentTag dataTag, ITextSnapshot snapshot) { var lineSpan = new LineSpan( snapshot.GetLineNumberFromPosition(dataTag.TeXBlock.Span.Start), snapshot.GetLineNumberFromPosition(dataTag.TeXBlock.Span.End)); if (adornment.LineSpan != lineSpan) { MarkAdornmentLines(adornment.LineSpan, null); //remove old MarkAdornmentLines(lineSpan, adornment); //add new } var lastLine = snapshot.GetLineFromLineNumber(lineSpan.LastLine); var lastLineWidthWithoutStartWhiteSpaces = (lastLine.Extent.Length - dataTag.TeXBlock.LastLineWhiteSpacesAtStart) * TextView.FormattedLineSource?.ColumnWidth; adornment.Update(dataTag, lineSpan, lastLineWidthWithoutStartWhiteSpaces); }
/// <summary> /// Rescans the part of the buffer affected by a change. /// Scans a contiguous sub-<paramref name="span"/> of a larger code span which starts at <paramref name="codeStartLine"/>. /// </summary> private void ApplyChange(Tokenizer tokenizer, ITextSnapshot snapshot, Span span, int codeStartLine, int codeStartLineOffset) { int firstLine = snapshot.GetLineNumberFromPosition(span.Start); int lastLine = snapshot.GetLineNumberFromPosition(span.Length > 0 ? span.End - 1 : span.End); Contract.Assert(codeStartLineOffset >= 0); Contract.Assert(firstLine >= codeStartLine); // find the closest line preceding firstLine for which we know categorizer state, stop at the codeStartLine: LineTokenization lineTokenization; firstLine = _tokenCache.IndexOfPreviousTokenization(firstLine, codeStartLine, out lineTokenization) + 1; object state = lineTokenization.State; int currentLine = firstLine; object previousState; while (currentLine < snapshot.LineCount) { previousState = _tokenCache.TryGetTokenization(currentLine, out lineTokenization) ? lineTokenization.State : null; _tokenCache[currentLine] = lineTokenization = TokenizeLine(tokenizer, snapshot, state, currentLine, (currentLine == codeStartLine) ? codeStartLineOffset : 0); state = lineTokenization.State; // stop if we visted all affected lines and the current line has no tokenization state or its previous state is the same as the new state: if (currentLine > lastLine && (previousState == null || previousState.Equals(state))) { break; } currentLine++; } // classification spans might have changed between the start of the first and end of the last visited line: int changeStart = snapshot.GetLineFromLineNumber(firstLine).Start; int changeEnd = (currentLine < snapshot.LineCount) ? snapshot.GetLineFromLineNumber(currentLine).End : snapshot.Length; if (changeStart < changeEnd) { var classificationChanged = ClassificationChanged; if (classificationChanged != null) { var args = new ClassificationChangedEventArgs(new SnapshotSpan(snapshot, new Span(changeStart, changeEnd - changeStart))); classificationChanged(this, args); } } }
public static Task <bool> CheckAvailabilityAsync(SnapshotSpan range, CancellationToken ct) { bool result = false; ITextSnapshot snapshot = range.Snapshot; int startLine = snapshot.GetLineNumberFromPosition(range.Start); int endLine = snapshot.GetLineNumberFromPosition(range.End); for (int i = startLine; i <= endLine; i++) { if (LineIsInclude(snapshot, i)) { result = true; break; } } return(Task.FromResult(result)); }
private ITextViewLine CreateAndAddLineFromPosition(SnapshotPoint position) { int lineNumber1Based = textSnapshot.GetLineNumberFromPosition(position) + 1; var line = textEditor.Document.GetLine(lineNumber1Based); var wrapper = textEditor.TextViewMargin.GetLayout(line); return(Add(lineNumber1Based, line, wrapper)); }
public void UpdateErrorList(ITextSnapshot snapshot) { lock (this) { if (_errorProvider != null && !m_disposed) { _errorProvider.SuspendRefresh(); // reduce flickering _errorProvider.Tasks.Clear(); foreach (var err in AllErrors) { var lineNum = 0; var columnNum = 0; if (err.Span != null) { var span = err.Span.GetSpan(snapshot); lineNum = snapshot.GetLineNumberFromPosition(span.Start.Position); var line = snapshot.GetLineFromPosition(span.Start.Position); columnNum = span.Start - line.Start; } else { lineNum = err.Line; columnNum = err.Column; } ErrorTask task = new ErrorTask() { Category = TaskCategory.BuildCompile, ErrorCategory = CategoryConversion(err.Category), Text = err.Message, Line = lineNum, Column = columnNum }; if (err.Filename != null) { task.Document = err.Filename; } else if (_document != null) { task.Document = _document.FilePath; } if (err.Category != ErrorCategory.ProcessError && err.Category != ErrorCategory.InternalError) { task.Navigate += new EventHandler(NavigateHandler); } _errorProvider.Tasks.Add(task); } _errorProvider.ResumeRefresh(); } } var chng = TagsChanged; if (chng != null) { chng(this, new SnapshotSpanEventArgs(new SnapshotSpan(snapshot, 0, snapshot.Length))); } }
private static ImmutableArray <BlockSpan> GetMultiLineRegions( #pragma warning disable IDE0060 // Remove unused parameter BlockStructureService service, #pragma warning restore IDE0060 // Remove unused parameter ImmutableArray <BlockSpan> regions, ITextSnapshot snapshot) { // Remove any spans that aren't multiline. var multiLineRegions = ArrayBuilder <BlockSpan> .GetInstance(); foreach (var region in regions) { if (region.TextSpan.Length > 0) { // Check if any clients produced an invalid OutliningSpan. If so, filter them // out and report a non-fatal watson so we can attempt to determine the source // of the issue. var snapshotSpan = snapshot.GetFullSpan().Span; var regionSpan = region.TextSpan.ToSpan(); if (!snapshotSpan.Contains(regionSpan)) { if (!s_exceptionReported) { s_exceptionReported = true; } continue; } var startLine = snapshot.GetLineNumberFromPosition(region.TextSpan.Start); var endLine = snapshot.GetLineNumberFromPosition(region.TextSpan.End); if (startLine != endLine) { multiLineRegions.Add(region); } } } // Make sure the regions are lexicographically sorted. This is needed // so we can appropriately parent them for BlockTags. // // Note we pass a IComparer instead of a Comparison to work around this // issue in ImmutableArray.Builder: https://github.com/dotnet/corefx/issues/11173 multiLineRegions.Sort(s_blockSpanComparer); return(multiLineRegions.ToImmutableAndFree()); }
private static ImmutableArray <BlockSpan> GetMultiLineRegions( BlockStructureService service, ImmutableArray <BlockSpan> regions, ITextSnapshot snapshot) { // Remove any spans that aren't multiline. var multiLineRegions = ArrayBuilder <BlockSpan> .GetInstance(); foreach (var region in regions) { if (region.TextSpan.Length > 0) { // Check if any clients produced an invalid OutliningSpan. If so, filter them // out and report a non-fatal watson so we can attempt to determine the source // of the issue. var snapshotSpan = snapshot.GetFullSpan().Span; var regionSpan = region.TextSpan.ToSpan(); if (!snapshotSpan.Contains(regionSpan)) { if (!s_exceptionReported) { s_exceptionReported = true; try { throw new InvalidOutliningRegionException(service, snapshot, snapshotSpan, regionSpan); } catch (InvalidOutliningRegionException e) when(FatalError.ReportAndCatch(e)) { } } continue; } var startLine = snapshot.GetLineNumberFromPosition(region.TextSpan.Start); var endLine = snapshot.GetLineNumberFromPosition(region.TextSpan.End); if (startLine != endLine) { multiLineRegions.Add(region); } } } return(multiLineRegions.ToImmutableAndFree()); }
// Find the lines that surround the span of the difference. Try to expand the span to // include both the previous and next lines so that we can show more context to the // user. private LineSpan GetLineSpan( ITextSnapshot snapshot, Span span) { var startLine = snapshot.GetLineNumberFromPosition(span.Start); var endLine = snapshot.GetLineNumberFromPosition(span.End); if (startLine > 0) { startLine--; } if (endLine < snapshot.LineCount) { endLine++; } return(LineSpan.FromBounds(startLine, endLine)); }
private void OnCaretPositionChanged(object sender, CaretPositionChangedEventArgs args) { SnapshotPoint oldPosition = args.OldPosition.BufferPosition; SnapshotPoint newPosition = args.NewPosition.BufferPosition; ITextSnapshot snapshot = this.textView.TextSnapshot; if (snapshot.GetLineNumberFromPosition(newPosition) != snapshot.GetLineNumberFromPosition(oldPosition)) { // Is the caret on a line that has been formatted by the view? ITextViewLine line = this.textView.Caret.ContainingTextViewLine; if (line.VisibilityState != VisibilityState.Unattached) { // Force the view to redraw so that (top of) the caret line has exactly the same position. this.textView.DisplayTextLineContainingBufferPosition(line.Start, line.Top, ViewRelativePosition.Top); } } }
private int FindLineAfterWhichToInsertDeclaration(ITextSnapshot snapshot, int p) { CodeNavigator navigator = new CodeNavigator(snapshot); IEnumerator <int> point = navigator.UpFrom(p).GetEnumerator(); int originalLine = snapshot.GetLineNumberFromPosition(p); int lineNumber = -1; bool notEOF; do { notEOF = point.MoveNext(); lineNumber = snapshot.GetLineNumberFromPosition(point.Current); }while(lineNumber == originalLine && notEOF); if (lineNumber == originalLine) { lineNumber = -1; } return(lineNumber); }
public LineTransform GetLineTransform(ITextViewLine line, double yposition, ViewRelativePosition placement) { // Vertically compress lines that are far from the caret (based on buffer lines, not view lines). ITextSnapshot snapshot = this.textView.TextSnapshot; int caretLineNumber = snapshot.GetLineNumberFromPosition(this.textView.Caret.Position.BufferPosition); int lineNumber = snapshot.GetLineNumberFromPosition(line.Start); int delta = Math.Abs(caretLineNumber - lineNumber); // Idea: Provide options to control these factors. [Bill, 7/17/2015] // Idea: Optionally, compress whitespace and non-alphanumeric lines more. [Bill, 7/17/2015] const int Group1Lines = 3; const int Group2Lines = Group1Lines + 5; const int Group3Lines = Group2Lines + 10; const double Group1ScaleFactor = 1.0; const double Group2ScaleFactor = 0.9; const double Group3ScaleFactor = 0.8; const double Group2ScaleDecrement = (Group1ScaleFactor - Group2ScaleFactor) / (Group2Lines - Group1Lines); const double Group3ScaleDecrement = (Group2ScaleFactor - Group3ScaleFactor) / (Group3Lines - Group2Lines); double scale; if (delta <= Group1Lines) { scale = Group1ScaleFactor; } else if (delta <= Group2Lines) { scale = Group1ScaleFactor - ((delta - (double)Group1Lines) * Group2ScaleDecrement); } else if (delta <= Group3Lines) { scale = Group2ScaleFactor - ((delta - (double)Group2Lines) * Group3ScaleDecrement); } else { scale = Group3ScaleFactor; } LineTransform result = new LineTransform(0.0, 0.0, scale); return(result); }
// parse the document from the start, and try to // figure out where the opening tag matching our closing tag starts private SnapshotSpan?FindOpeningTag(ITextSnapshot snapshot, int searchEnd, string searchFor) { String textToSearch = snapshot.GetText(0, searchEnd); int origLineNum = snapshot.GetLineNumberFromPosition(searchEnd); using (SgmlReader reader = new SgmlReader()) { reader.InputStream = new StringReader(textToSearch); reader.WhitespaceHandling = WhitespaceHandling.All; try { Stack <int> openingPositions = new Stack <int>(); while (reader.Read()) { if (reader.LocalName != searchFor) { continue; } if (reader.NodeType == XmlNodeType.Element && !reader.IsEmptyElement) { // find close to where the tag starts int lineNum = reader.LineNumber - 1; var line = snapshot.GetLineFromLineNumber(lineNum); int position = line.Start.Position + reader.LinePosition - searchFor.Length; position = BacktrackToLessThan(snapshot, position); String textFound = snapshot.GetText(position, 10); openingPositions.Push(position); } else if (reader.NodeType == XmlNodeType.EndElement) { if (openingPositions.Count <= 0) { // document is malformed, so just get the heck out return(null); } var line = snapshot.GetLineFromLineNumber(reader.LineNumber - 1); int position = line.Start.Position + reader.LinePosition; if (position >= searchEnd) { break; } openingPositions.Pop(); } } // done, last if (openingPositions.Count > 0) { int position = openingPositions.Pop(); return(new SnapshotSpan(snapshot, position, searchFor.Length + 2)); } } catch (Exception ex) { Trace.WriteLine(String.Format("Exception while parsing document: {0}.", ex.ToString())); } } return(null); }
private IList <OutliningSpan> GetMultiLineRegions(IList <OutliningSpan> regions, ITextSnapshot snapshot) { // Remove any spans that aren't multiline. var multiLineRegions = new List <OutliningSpan>(regions.Count); foreach (var region in regions) { if (region != null && region.TextSpan.Length > 0) { var startLine = snapshot.GetLineNumberFromPosition(region.TextSpan.Start); var endLine = snapshot.GetLineNumberFromPosition(region.TextSpan.End); if (startLine != endLine) { multiLineRegions.Add(region); } } } return(multiLineRegions); }
private IList <OutliningSpan> GetMultiLineRegions(IOutliningService service, IList <OutliningSpan> regions, ITextSnapshot snapshot) { // Remove any spans that aren't multiline. var multiLineRegions = new List <OutliningSpan>(regions.Count); foreach (var region in regions) { if (region != null && region.TextSpan.Length > 0) { // Check if any clients produced an invalid OutliningSpan. If so, filter them // out and report a non-fatal watson so we can attempt to determine the source // of the issue. var snapshotSpan = snapshot.GetFullSpan().Span; var regionSpan = region.TextSpan.ToSpan(); if (!snapshotSpan.Contains(regionSpan)) { if (!exceptionReported) { exceptionReported = true; try { throw new InvalidOutliningRegionException(service, snapshot, snapshotSpan, regionSpan); } catch (InvalidOutliningRegionException e) when(FatalError.ReportWithoutCrash(e)) { } } continue; } var startLine = snapshot.GetLineNumberFromPosition(region.TextSpan.Start); var endLine = snapshot.GetLineNumberFromPosition(region.TextSpan.End); if (startLine != endLine) { multiLineRegions.Add(region); } } } return(multiLineRegions); }
public int GetMinNumberOfWhitespacesBeforeCommentPrefixes(ITextSnapshot snapshot) { var firstLineIndex = snapshot.GetLineNumberFromPosition(Span.Start); var lastLineIndex = snapshot.GetLineNumberFromPosition(Span.End); int min = int.MaxValue; for (int lineIndex = firstLineIndex; lineIndex <= lastLineIndex; lineIndex++) { var line = snapshot.GetLineFromLineNumber(lineIndex); //TODO perf int whitespaces = line.GetText().NumberOfWhiteSpaceCharsOnStartOfLine(); if (whitespaces < min) { min = whitespaces; } } return(min); }
protected static IEnumerable <ITextSnapshotLine> GetSpanLines(SnapshotSpan span) { ITextSnapshot snapshot = span.Snapshot; if (!snapshot.TextBuffer.EditInProgress) { // Note: The snapshot is usually for the entire file. We only need to (re)classify a small span of it usually, // so we should not use snapshot.Lines. We'll just get the lines covered by the span's [Start, End) range. int startLineNumber = snapshot.GetLineNumberFromPosition(span.Start.Position); int endLineNumber = snapshot.GetLineNumberFromPosition(span.End.Position - 1); for (int lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) { ITextSnapshotLine line = snapshot.GetLineFromLineNumber(lineNumber); if (line.Length > 0) { yield return(line); } } } }
private static IProjectionBuffer CreateProjectionBuffer( IProjectionBufferFactoryService factoryService, IContentTypeRegistryService registryService, IEditorOptions editorOptions, ITextSnapshot snapshot, string separator, object suffixOpt, bool trim, params LineSpan[] exposedLineSpans) { var spans = new List<object>(); if (exposedLineSpans.Length > 0) { if (exposedLineSpans[0].Start > 0 && !string.IsNullOrEmpty(separator)) { spans.Add(separator); spans.Add(editorOptions.GetNewLineCharacter()); } var snapshotSpanRanges = CreateSnapshotSpanRanges(snapshot, exposedLineSpans); var indentColumn = trim ? DetermineIndentationColumn(editorOptions, snapshotSpanRanges.Flatten()) : 0; foreach (var snapshotSpanRange in snapshotSpanRanges) { foreach (var snapshotSpan in snapshotSpanRange) { var line = snapshotSpan.Snapshot.GetLineFromPosition(snapshotSpan.Start); var indentPosition = line.GetLineOffsetFromColumn(indentColumn, editorOptions) + line.Start; var mappedSpan = new SnapshotSpan(snapshotSpan.Snapshot, Span.FromBounds(indentPosition, snapshotSpan.End)); var trackingSpan = mappedSpan.CreateTrackingSpan(SpanTrackingMode.EdgeExclusive); spans.Add(trackingSpan); // Add a newline between every line. if (snapshotSpan != snapshotSpanRange.Last()) { spans.Add(editorOptions.GetNewLineCharacter()); } } // Add a separator between every set of lines. if (snapshotSpanRange != snapshotSpanRanges.Last()) { spans.Add(editorOptions.GetNewLineCharacter()); spans.Add(separator); spans.Add(editorOptions.GetNewLineCharacter()); } } if (snapshot.GetLineNumberFromPosition(snapshotSpanRanges.Last().Last().End) < snapshot.LineCount - 1) { spans.Add(editorOptions.GetNewLineCharacter()); spans.Add(separator); } } if (suffixOpt != null) { if (spans.Count >= 0) { if (!separator.Equals(spans.Last())) { spans.Add(editorOptions.GetNewLineCharacter()); spans.Add(separator); } spans.Add(editorOptions.GetNewLineCharacter()); } spans.Add(suffixOpt); } return factoryService.CreateProjectionBuffer( projectionEditResolver: null, sourceSpans: spans, options: ProjectionBufferOptions.None, contentType: registryService.GetContentType(ShaderPreviewContentType)); }
/// <summary> /// Parse a text snapshot into markdown sections. This is only part of the markdown parser that is really aware of the editor, /// but it keeps us from re-creating all the "GetLineFromLineNumber"-type methods. /// </summary> /// <param name="snapshot"></param> /// <returns></returns> public static IEnumerable<Token> ParseMarkdownSections(ITextSnapshot snapshot) { string text = snapshot.GetText(); List<Tuple<int, TokenType>> startPoints = new List<Tuple<int, TokenType>>(ParseMarkdownParagraph(text).Where(t => IsHeaderToken(t)) .Select(t => Tuple.Create(t.Span.Start, t.TokenType))); List<Token> sections = new List<Token>(); Stack<Tuple<int, TokenType>> regions = new Stack<Tuple<int, TokenType>>(); foreach (var start in startPoints) { int previousLineNumber = Math.Max(0, snapshot.GetLineNumberFromPosition(start.Item1) - 1); int end = snapshot.GetLineFromLineNumber(previousLineNumber).End; while (regions.Count > 0 && regions.Peek().Item2 >= start.Item2) { var region = regions.Pop(); var span = Span.FromBounds(region.Item1, end); sections.Add(new Token(region.Item2, span)); } regions.Push(start); } while (regions.Count > 0) { var region = regions.Pop(); var span = Span.FromBounds(region.Item1, snapshot.Length); sections.Add(new Token(region.Item2, span)); } sections.Sort((left, right) => { if (left.Span.Start != right.Span.Start) return left.Span.Start.CompareTo(right.Span.Start); return right.Span.Length.CompareTo(left.Span.Length); }); return sections; }
private static bool TokensSkippedLines(ITextSnapshot snapshot, int endLinePrevious, IToken token) { int startLineCurrent = snapshot.GetLineNumberFromPosition(token.StartIndex); return startLineCurrent > endLinePrevious + 1; }
public static Parameter[] GetFunctionParameters(int position, ITextSnapshot capture, bool isAboveFunction = false) { int openFunctionLine = capture.GetLineNumberFromPosition(position - 1); if (isAboveFunction) { openFunctionLine += 1; } else { openFunctionLine -= 1; } ITextSnapshotLine line = capture.GetLineFromLineNumber(openFunctionLine); string curLine = line.Extent.GetText(); openFunctionLine = StubUtils.GetFunctionDeclarationLineNumber(capture, openFunctionLine, isAboveFunction); //Not immediately after a function declaration if (openFunctionLine == -1) return new Parameter[0]; curLine = capture.GetLineFromLineNumber(openFunctionLine).GetText(); int ftnIndex = StubUtils.javaScriptFnRegex.Match(curLine).Index; int firstParenPosition = -1; if (curLine.IndexOf('(', ftnIndex) > -1) { firstParenPosition = capture.GetLineFromLineNumber(openFunctionLine).Start + curLine.IndexOf('(', ftnIndex) + 1; } else { do { openFunctionLine++; curLine = capture.GetLineFromLineNumber(openFunctionLine).GetText(); } while (!curLine.Contains("(")); firstParenPosition = capture.GetLineFromLineNumber(openFunctionLine).Start + curLine.IndexOf('(') + 1; } var parenBlock = GetCompleteParenBlock(capture, openFunctionLine, firstParenPosition); if (parenBlock == null) { return new Parameter[0]; } parenBlock = RemoveComments(parenBlock); return parenBlock .Split(',') .Select(param => { var result = Parameter.Parse(param); if (StubUtils.contentTypeName.Equals("JavaScript")) { result.Type = "type"; } return result; }) .ToArray(); }
private int FindLineAfterWhichToInsertFieldDeclaration(ITextSnapshot snapshot, int p) { CodeNavigator navigator = new CodeNavigator(snapshot); foreach (int significantPoint in navigator.UpFrom(p)) { if (navigator.IsInClassScope(significantPoint)) return snapshot.GetLineNumberFromPosition(significantPoint); } return -1; }
protected virtual bool IsMultilineToken(ITextSnapshot snapshot, ITokenSource lexer, IToken token) { Lexer lexerLexer = lexer as Lexer; if (lexerLexer != null && lexerLexer.Line >= token.Line) return false; int startLine = snapshot.GetLineNumberFromPosition(token.StartIndex); int stopLine = snapshot.GetLineNumberFromPosition(token.StopIndex + 1); return startLine != stopLine; }
public void ReportParseErrors(IParseResult parseResult, ITextSnapshot snapshot) { _errorListProvider.SuspendRefresh(); try { // remove any previously created errors to get a clean start ClearErrors(); var messages = (CompilerMessageList)parseResult.CompilerMessages; foreach (var error in messages.GetMessages()) { // creates the instance that will be added to the Error List var nSpan = error.Location.Span; var span = new Span(nSpan.StartPos, nSpan.Length); if (span.Start >= snapshot.Length) continue; ErrorTask task = new ErrorTask(); task.Category = TaskCategory.All; task.Priority = TaskPriority.Normal; task.Document = _textBuffer.Properties.GetProperty<ITextDocument>(typeof(ITextDocument)).FilePath; task.ErrorCategory = TranslateErrorCategory(error); task.Text = error.Text; task.Line = snapshot.GetLineNumberFromPosition(span.Start); task.Column = span.Start - snapshot.GetLineFromLineNumber(task.Line).Start; task.Navigate += OnTaskNavigate; _errorListProvider.Tasks.Add(task); _previousErrors.Add(task); var trackingSpan = snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeNegative); _squiggleTagger.CreateTagSpan(trackingSpan, new ErrorTag("syntax error", error.Text)); _previousSquiggles.Add(new TrackingTagSpan<IErrorTag>(trackingSpan, new ErrorTag("syntax error", error.Text))); } } finally { _errorListProvider.ResumeRefresh(); } }
public static bool ShouldCreateReturnTag(int position, ITextSnapshot capture, bool isAboveFunction = false) { if (Options.ReturnGenerationOption == ReturnTagGenerationSetting.Always) return true; if (Options.ReturnGenerationOption == ReturnTagGenerationSetting.Never) return false; bool hasReturn = false; bool newFunction = false; bool functionClosed = false; bool hasComment = false; int lineNumber = capture.GetLineNumberFromPosition(position - 1); string lineText = capture.GetLineFromLineNumber(lineNumber).GetText(); if (isAboveFunction) { lineNumber++; } else { lineNumber--; } bool inFunction = GetFunctionDeclarationLineNumber(capture, lineNumber, isAboveFunction) >= 0; if (!inFunction) return false; if (isAboveFunction) { lineNumber = GetNextOpenCurlyBrace(lineNumber, capture); } if (lineNumber == -1) { return false; } int functionsOpen = 0; int openBracket = 0; for (int i = lineNumber; i < capture.LineCount; i++) { lineText = capture.GetLineFromLineNumber(i).GetText(); //HANDLE COMMENTS if (lineText.Contains("/*") && lineText.Contains("*/") && lineText.LastIndexOf("/*") > lineText.LastIndexOf("*/")) { hasComment = true; } else if (lineText.Contains("/*") && lineText.Contains("*/")) { hasComment = false; } else if (lineText.Contains("/*")) { hasComment = true; } if (hasComment && lineText.Contains("*/")) { if (!lineText.Contains("/*") || lineText.LastIndexOf("/*") <= lineText.LastIndexOf("*/")) hasComment = false; } else if (hasComment || String.IsNullOrEmpty(lineText.Trim())) { continue; } lineText = RemoveComments(lineText); //END COMMENT HANDLING //HANDLE BRACKETS - "{ }" if (javaScriptFnRegex.IsMatch(lineText) && lineText.Contains("{")) { //adds an open function and an open bracket. functionsOpen++; } else if (javaScriptFnRegex.IsMatch(lineText)) { //states that there is a new function open without an open bracket. newFunction = true; } else if (newFunction && lineText.Contains("{")) { //states that there is no longer a new function and adds an open //bracket and open function. newFunction = false; functionsOpen++; } if (lineText.Contains("{")) { //Adds an open bracket. openBracket++; } bool isInlineFunction = false; if (lineText.Contains("}")) { //If function is closed on same line as closing bracket if (functionsOpen == 1 && returnRegex.IsMatch(lineText)) { hasReturn = true; break; } else if (returnRegex.IsMatch(lineText)) { isInlineFunction = true; } //Decrements both the number of open brackets and functions if they are equal. //This means the number of open brackets are the same as the number of open functions. //Otherwise it just decrements the number of open brackets. if (openBracket == functionsOpen) { functionsOpen--; } openBracket--; } if (functionsOpen == 0) functionClosed = true; if (functionsOpen == 1 && returnRegex.IsMatch(lineText) && !isInlineFunction) { hasReturn = true; break; } else if (functionClosed) { break; } } return hasReturn; }
/// <summary> /// Gets the number of tabs from the beginning of the line. /// </summary> /// <param name="lastSlashPosition"></param> /// <param name="capture">The snapshot to use as the context of the line.</param> /// <returns></returns> public static string GetIndention(int lastSlashPosition, ITextSnapshot capture, bool isAboveFunction = false) { int lineNum = capture.GetLineNumberFromPosition(lastSlashPosition); if (isAboveFunction) { lineNum++; } else { lineNum--; } lineNum = GetFunctionDeclarationLineNumber(capture, lineNum, isAboveFunction); string space = capture.GetLineFromLineNumber(lineNum).GetText(); int leadingSpace = space.Length - space.TrimStart().Length; space = space.Substring(0, leadingSpace); if (isAboveFunction) { return space; } return space + GetTab(); }
private int FindLineAfterWhichToInsertDeclaration(ITextSnapshot snapshot, int p) { CodeNavigator navigator = new CodeNavigator(snapshot); IEnumerator<int> point = navigator.UpFrom(p).GetEnumerator(); int originalLine = snapshot.GetLineNumberFromPosition(p); int lineNumber = -1; bool notEOF; do { notEOF = point.MoveNext(); lineNumber = snapshot.GetLineNumberFromPosition(point.Current); } while( lineNumber == originalLine && notEOF) ; if (lineNumber == originalLine) lineNumber = -1; return lineNumber; }
/// <summary> /// Rescans the part of the buffer affected by a change. /// Scans a contiguous sub-<paramref name="span"/> of a larger code span which starts at <paramref name="codeStartLine"/>. /// </summary> private void ApplyChange(Tokenizer tokenizer, ITextSnapshot snapshot, Span span) { int firstLine = snapshot.GetLineNumberFromPosition(span.Start); int lastLine = snapshot.GetLineNumberFromPosition(span.Length > 0 ? span.End - 1 : span.End); Contract.Assert(firstLine >= 0); // find the closest line preceding firstLine for which we know categorizer state, stop at the codeStartLine: LineTokenization lineTokenization; firstLine = _tokenCache.IndexOfPreviousTokenization(firstLine, 0, out lineTokenization) + 1; object state = lineTokenization.State; int currentLine = firstLine; object previousState; while (currentLine < snapshot.LineCount) { previousState = _tokenCache.TryGetTokenization(currentLine, out lineTokenization) ? lineTokenization.State : null; _tokenCache[currentLine] = lineTokenization = TokenizeLine(tokenizer, snapshot, state, currentLine); state = lineTokenization.State; // stop if we visted all affected lines and the current line has no tokenization state or its previous state is the same as the new state: if (currentLine > lastLine && (previousState == null || previousState.Equals(state))) { break; } currentLine++; } // classification spans might have changed between the start of the first and end of the last visited line: int changeStart = snapshot.GetLineFromLineNumber(firstLine).Start; int changeEnd = (currentLine < snapshot.LineCount) ? snapshot.GetLineFromLineNumber(currentLine).End : snapshot.Length; if (changeStart < changeEnd) { var classificationChanged = ClassificationChanged; if (classificationChanged != null) { var args = new ClassificationChangedEventArgs(new SnapshotSpan(snapshot, new Span(changeStart, changeEnd - changeStart))); classificationChanged(this, args); } } }
public static string[] GetFunctionParameters(int position, ITextSnapshot capture, bool isAboveFunction = false) { int openFunctionLine = capture.GetLineNumberFromPosition(position - 1); if (isAboveFunction) { openFunctionLine += 1; } else { openFunctionLine -= 1; } ITextSnapshotLine line = capture.GetLineFromLineNumber(openFunctionLine); string prevLine = line.Extent.GetText(); openFunctionLine = StubUtils.GetFunctionDeclarationLineNumber(capture, openFunctionLine, isAboveFunction); //Not immediately after a function declaration if (openFunctionLine == -1) return new string[0]; prevLine = capture.GetLineFromLineNumber(openFunctionLine).GetText(); int ftnIndex = StubUtils.javaScriptFnRegex.Match(prevLine).Index; int firstParenPosition = -1; if (prevLine.IndexOf('(', ftnIndex) > -1) { firstParenPosition = capture.GetLineFromLineNumber(openFunctionLine).Start + prevLine.IndexOf('(', ftnIndex) + 1; } else { do { openFunctionLine++; prevLine = capture.GetLineFromLineNumber(openFunctionLine).GetText(); } while (!prevLine.Contains("(")); firstParenPosition = capture.GetLineFromLineNumber(openFunctionLine).Start + prevLine.IndexOf('(') + 1; } int lastParenPosition = -1; if (prevLine.IndexOf(')') > 0) { lastParenPosition = capture.GetLineFromLineNumber(openFunctionLine).Start + prevLine.IndexOf(')', prevLine.IndexOf('(')); } else { do { openFunctionLine++; prevLine = capture.GetLineFromLineNumber(openFunctionLine).GetText(); } while (!prevLine.Contains(")")); lastParenPosition = capture.GetLineFromLineNumber(openFunctionLine).Start + prevLine.IndexOf(")"); } return StubUtils .RemoveComments(capture .GetText() .Substring(firstParenPosition, (lastParenPosition - firstParenPosition))) .Split(',') .Select(param => param.Trim()) .ToArray(); }
private int FindLineBeforeWhichToInsertMethodStatement(ITextSnapshot snapshot, int p) { CodeNavigator navigator = new CodeNavigator(snapshot); int lastLineOfMethod = -1; foreach (int significantPoint in navigator.DownFrom(p)) { lastLineOfMethod = significantPoint; } if (lastLineOfMethod > 0) return snapshot.GetLineNumberFromPosition(lastLineOfMethod); return -1; }
// Find the lines that surround the span of the difference. Try to expand the span to // include both the previous and next lines so that we can show more context to the // user. private LineSpan GetLineSpan( ITextSnapshot snapshot, Span span) { var startLine = snapshot.GetLineNumberFromPosition(span.Start); var endLine = snapshot.GetLineNumberFromPosition(span.End); if (startLine > 0) { startLine--; } if (endLine < snapshot.LineCount) { endLine++; } return LineSpan.FromBounds(startLine, endLine); }
private static bool ShouldWrapPrelim( bool optionsAutoWrapEnabled, int optionsAvoidWrappingBeforeLine, INormalizedTextChangeCollection changes, ITextSnapshot snapshot, ITextBuffer buffer, CaretPosition caretPosition, out SnapshotPoint caretPoint, out int firstLine) { caretPoint = default(SnapshotPoint); firstLine = -1; if (!optionsAutoWrapEnabled) { return false; } if (!buffer.CheckEditAccess()) { return false; } // The auto-wrap should only apply during simple typing. Region // edits (simultaneous multi-line typing) could lead to truly bizarre // wrapping behavior, so it really doesn't make sense. if (changes.Count > 1) { return false; } // Need a better (more testable!) way to get the editing state // (change, caret, etc.) out. Perhaps we just take the hit and get // all of these up front instead of only calculating them as needed? var change = changes[0]; caretPoint = caretPosition.Point.GetPoint(snapshot, caretPosition.Affinity).GetValueOrDefault(); // If the caret isn't near the change, this was an undo, or other operation // we shouldn't wrap on! if ((caretPoint.Snapshot != snapshot) || (caretPoint < change.NewPosition) || (caretPoint > change.NewEnd)) { return false; } firstLine = snapshot.GetLineNumberFromPosition(change.NewPosition); // If we're in the "don't auto-wrap" leading lines, bail. if (firstLine < optionsAvoidWrappingBeforeLine) { return false; } return true; }
/// <summary> /// Determines if range is large enough to be outlined /// </summary> private static bool OutlineRange(ITextSnapshot snapshot, ITextRange range, out int startLineNumber, out int endLineNumber) { int start = Math.Max(0, range.Start); int end = Math.Min(range.End, snapshot.Length); startLineNumber = endLineNumber = 0; if (start < end) { startLineNumber = snapshot.GetLineNumberFromPosition(start); endLineNumber = snapshot.GetLineNumberFromPosition(end); return endLineNumber - startLineNumber + 1 >= _minLinesToOutline; } return false; }
private static void BuildRegions(OutlineRegionCollection newRegions, ITextSnapshot snapshot) { // Figure out regions based on line indent if (snapshot.LineCount == 0) return; var regionStack = new Stack<CodeBlock>(); var lineLengths = new int[snapshot.LineCount]; int lastBlockIndent = 0; for (int i = 0; i < snapshot.LineCount; i++) { var line = snapshot.GetLineFromLineNumber(i); var lineText = line.GetText(); if (String.IsNullOrWhiteSpace(lineText)) { lineLengths[i] = 0; continue; } lineLengths[i] = line.Length; int indent = GetLineIndent(line); if (regionStack.Count > 0) lastBlockIndent = regionStack.Peek().Indent; else lastBlockIndent = 0; if (indent <= lastBlockIndent) { // We add regions optimistically since any line can // start a new region if lines below it are indented // deeper that this line. while (regionStack.Count > 0) { // If we have line with the same indent, remove previously added region // and replace it with a new one potentially starting with the current line. var prevCodeBlock = regionStack.Pop(); int startLine = snapshot.GetLineNumberFromPosition(prevCodeBlock.Start); // Trim empty lines int j = i - 1; for (; j >= 0; j--) { if (lineLengths[j] > 0) break; } j++; if (j > 0 && j - startLine >= _minLinesToOutline) { var prevLine = snapshot.GetLineFromLineNumber(j - 1); if (prevCodeBlock.Start < prevLine.End) newRegions.Add(OutlineRegion.FromBounds(snapshot.TextBuffer, prevCodeBlock.Start, prevLine.End)); } if (regionStack.Count > 0) { prevCodeBlock = regionStack.Peek(); if (prevCodeBlock.Indent < indent) break; } } } lastBlockIndent = indent; regionStack.Push(new CodeBlock(line.Start, indent)); } // Note that last region may be bogus since we add regions optimistically. // Remove last region if its indent is the same as the line before it if (regionStack.Count > 0) { var codeBlock = regionStack.Peek(); var lineNumber = snapshot.GetLineNumberFromPosition(codeBlock.Start); if (lineNumber > 0) { var prevLine = snapshot.GetLineFromLineNumber(lineNumber - 1); int indent = GetLineIndent(prevLine); if (indent == codeBlock.Indent) regionStack.Pop(); } } while (regionStack.Count > 0) { var codeBlock = regionStack.Pop(); int startLine = snapshot.GetLineNumberFromPosition(codeBlock.Start); if (snapshot.LineCount - startLine >= _minLinesToOutline) { newRegions.Add(OutlineRegion.FromBounds(snapshot.TextBuffer, codeBlock.Start, snapshot.Length)); } } }