/// <summary> /// Determines whether or not the user just entered a triple slash (///) on a blank line. /// </summary> /// <returns>True if a triple slash occurred on an otherwise blank line, false if it /// didn't.</returns> /// <remarks> /// I tried to make this implementation as robust as possible; it actually figures out where /// in the current line the caret lives and adds the "/" character to the line at that location /// before checking to see if a triple slash occurred or not. This should get rid of any weird /// behavior where a triple slash gets incorrectly triggered when there isn't actually one /// on the line (e.g. if there's whitespace between the forward slash characters). As far as /// I can tell, this really does only get triggered if there are three contiguous slashes on /// an otherwise blank line (leading or trailing whitespace doesn't count). /// </remarks> private bool UserTypedTripleSlash() { // Convert the caret's location in screen (pixel) space to the corresponding character index in the editor text box's // buffer. We need this to figure out the location of the caret in the current line. CaretPosition caretPosition = TextView.Caret.Position; SnapshotPoint?snapshotPointWrapper = caretPosition.Point.GetPoint(TextView.TextSnapshot, caretPosition.Affinity); if (snapshotPointWrapper == null) { return(false); } SnapshotPoint snapshotPoint = snapshotPointWrapper.Value; // Get the current line being edited, along with its starting position in the text snapshot ITextSnapshotLine currentLine = snapshotPoint.GetContainingLine(); string lineText = currentLine.GetTextIncludingLineBreak(); int lineStart = currentLine.Start; // Add the forward slash to the line, based on where the caret is int caretIndexInLine = snapshotPoint - lineStart; lineText = lineText.Insert(caretIndexInLine, "/"); // Return whether or not the new line is a triple slash return(lineText.Trim().Equals("///")); }
public int PerformMove(IWpfTextView view, ITextSnapshotLine lineToSwap, int insertPosition) { var insertedText = lineToSwap.GetTextIncludingLineBreak(); if(insertPosition == view.TextSnapshot.Length) { // We don't want ot move the line break if the insert position is the last character of the // document but also the first character of the line (i.e. an empty line at the end of the document) var lineUnderInsertPosition = view.TextSnapshot.GetLineFromPosition(insertPosition); if (lineUnderInsertPosition.Length > 0) { // Move the line break to the start of the text to insert insertedText = (Environment.NewLine + insertedText).Substring(0, insertedText.Length); } } using (var edit = view.TextBuffer.CreateEdit()) { edit.Delete(lineToSwap.Start, lineToSwap.LengthIncludingLineBreak); edit.Insert(insertPosition, insertedText); edit.Apply(); } return -lineToSwap.LengthIncludingLineBreak; }
int?ISmartIndent.GetDesiredIndentation(ITextSnapshotLine line) { line = GetPreviousNonEmpty(line); int whitespace = 0; if (line != null) { string linestr = line.GetTextIncludingLineBreak(); int tabs = linestr.Count(x => { return(x == '\t'); }); int length = (linestr.Length - tabs) + (tabs * 4); string scope = linestr.Replace("\n", ""); scope = scope.Replace("\r", ""); scope = scope.Replace("\t", ""); scope = scope.TrimStart(); bool isscope = scope.Length > 0; bool beginscope = isscope && scope.Last() == '{'; bool endscope = isscope && scope.Last() == '}'; if (scope.Length == 1) { if (beginscope) { // if ((length % 4) != 0) // length += 4; return((int)(length / 4 * 4)); } } whitespace = linestr.Length - linestr.TrimStart(' ').Length; whitespace += (linestr.Length - linestr.TrimStart('\t').Length) * 4; /*if (beginscope) * { * whitespace += 4; * }*/ } whitespace = (whitespace / 4) * 4; return(whitespace); /*SQDeclaration d = _languageService.LanguageInstance.Dive(line.Snapshot.TextBuffer, line.LineNumber, line.Length); * if (d == null || d is SQDeclaration.SQFile) * return 0; * if (d.ScopeSpan.iEndLine <= line.LineNumber) * { * int level = d.Level; * return 4 * level; * } * else * { * int level = d.Level + 1; * return 4 * level; * }*/ }
public LineBuffer(ITextSnapshotLine line) { this.line = line; if (line.LengthIncludingLineBreak <= BufferSize) { this.contents = line.GetTextIncludingLineBreak(); this.extent = new Span(0, line.LengthIncludingLineBreak); } else { this.extent = new Span(0, 0); } }
public int PerformMove(IWpfTextView view, ITextSnapshotLine lineToSwap, int insertPosition) { var insertedText = lineToSwap.GetTextIncludingLineBreak(); var deleteStartPosition = lineToSwap.Start.Position; if(lineToSwap.End == lineToSwap.EndIncludingLineBreak) { insertedText = insertedText + Environment.NewLine; deleteStartPosition = deleteStartPosition - Environment.NewLine.Length; } using (var edit = view.TextBuffer.CreateEdit()) { edit.Delete(deleteStartPosition, insertedText.Length); edit.Insert(insertPosition, insertedText); edit.Apply(); } return insertedText.Length; }
private void UpdateCachedLine() { if (_explicitCache) { return; } if (_currentSnapshotLine == null || Index < _currentSnapshotLineStartIndex || Index >= _currentSnapshotLineStartIndex + _currentSnapshotLine.Length) { if (Index >= 0 && Index < Count) { ITextSnapshotLine line = Snapshot.GetLineFromPosition(Index); _currentSnapshotLineStartIndex = line.Start; _currentSnapshotLine = line.GetTextIncludingLineBreak(); } else { _currentSnapshotLine = null; _currentSnapshotLineStartIndex = 0; } } }
private void Jump(JumpDirection direction) { // as with the standard caret moving operations (click, arrow keys, etc.) // we clear our current selection when we jump View.Selection.Clear(); // rules: // if the line we begin on contains text, or the following line contains text, // navigate to the next blank line // if the line we begin on is blank, and the next line is also blank, // navigate to the line preceding the next line that contains text // if we find no suitable lines, we navigate to the last line CaretPosition startingPos = View.Caret.Position; ITextBuffer buffer = View.TextBuffer; ITextSnapshot currentSnapshot = buffer.CurrentSnapshot; SnapshotPoint start = startingPos.BufferPosition; ITextSnapshotLine previousLine = start.GetContainingLine(); ITextSnapshotLine targetLine = null; bool previousLineIsBlank = string.IsNullOrWhiteSpace(previousLine.GetTextIncludingLineBreak()); int startLineNo = currentSnapshot.GetLineNumberFromPosition(start.Position); int lineInc = (int)direction; int firstLine = startLineNo + lineInc; for (int i = firstLine; i >= 0 && i < currentSnapshot.LineCount; i += lineInc) { ITextSnapshotLine line = currentSnapshot.GetLineFromLineNumber(i); string lineContents = line.GetTextIncludingLineBreak(); bool lineIsBlank = string.IsNullOrWhiteSpace(lineContents); if (lineIsBlank) { if (!previousLineIsBlank && i != firstLine) { // found our next blank line beyond our text block targetLine = (JumpOutsideEdge) ? line : previousLine; break; } } else if (!SkipClosestEdge && previousLineIsBlank && i != firstLine) { // found our text block, go to the blank line right before it targetLine = (JumpOutsideEdge) ? previousLine : line; break; } previousLine = line; previousLineIsBlank = lineIsBlank; } if (targetLine != null) { VirtualSnapshotPoint finalPosition; if (JumpOutsideEdge) { // move the caret to the blank line indented with the appropriate number of virtual spaces int?virtualSpaces = SmartIndentation.GetDesiredIndentation(View, targetLine); finalPosition = new VirtualSnapshotPoint(targetLine.Start, virtualSpaces.GetValueOrDefault()); if (!finalPosition.IsInVirtualSpace) { // our line has some 'meaningful' whitespace, go to end instead finalPosition = new VirtualSnapshotPoint(targetLine.End); } } else { string lineString = targetLine.GetTextIncludingLineBreak(); int offset = lineString.TakeWhile(c => char.IsWhiteSpace(c)).Count(); finalPosition = new VirtualSnapshotPoint(targetLine, offset); } View.Caret.MoveTo(finalPosition); } else { // we found no suitable line so just choose BOF or EOF depending on the direction we were moving if (direction == JumpDirection.Up) { View.Caret.MoveTo(previousLine.Start); } else { View.Caret.MoveTo(previousLine.End); } } // scroll our view to the new caret position View.Caret.EnsureVisible(); }
internal static string DefaultGetLineTextCallback(ITextSnapshotLine line) { return(line.GetTextIncludingLineBreak()); }
public override void Execute() { ITextSnapshot snapshot = _view.TextSnapshot; if (snapshot != snapshot.TextBuffer.CurrentSnapshot) { return; } if (_view.Selection.IsEmpty) { // nothing is selected, duplicate current line using (var edit = snapshot.TextBuffer.CreateEdit()) { ITextSnapshotLine line = snapshot.GetLineFromPosition(_view.Selection.AnchorPoint.Position.Position); edit.Insert(line.EndIncludingLineBreak.Position, line.GetTextIncludingLineBreak()); edit.Apply(); } } else { // duplicate selection // If we have a multi-line stream slection, it is likely that the user wants to // duplicate all lines in the selection. Extend the selection to accomplish this // if necessary. if (_view.Selection.Mode == TextSelectionMode.Stream) { var startLine = snapshot.GetLineFromPosition(_view.Selection.Start.Position.Position); var endLine = snapshot.GetLineFromPosition(_view.Selection.End.Position.Position); if (startLine.LineNumber != endLine.LineNumber && (!_view.Selection.IsReversed || _view.Selection.End.Position != endLine.End)) { // selection spans multiple lines var newSelStart = _view.Selection.Start.Position; var newSelEnd = _view.Selection.End.Position; if (startLine.Start < newSelStart) { newSelStart = startLine.Start; } if (endLine.Start != newSelEnd) { newSelEnd = endLine.EndIncludingLineBreak; } if (_view.Selection.Start.Position != newSelStart || _view.Selection.End.Position != newSelEnd) { _view.Selection.Select(new SnapshotSpan(newSelStart, newSelEnd), false); _view.Caret.MoveTo(newSelEnd, PositionAffinity.Predecessor); } } } // When text is inserted into a pre-existing selection, VS extends the selection // to also contain the inserted text. This is not desired in this case, so save // the current selection so we can revert to it later. var initAnchor = _view.Selection.AnchorPoint; var initActive = _view.Selection.ActivePoint; using (var edit = snapshot.TextBuffer.CreateEdit()) { // Unless this is a box selection there will likely only be one span. // Iterate backwards over the spans so we don't have to change the insertion point // to compensate for already-inserted text. foreach (var span in _view.Selection.SelectedSpans.Reverse()) { if (!span.IsEmpty) { edit.Insert(span.End.Position, span.GetText()); } } edit.Apply(); } var newAnchor = initAnchor.TranslateTo(_view.TextSnapshot, PointTrackingMode.Negative); var newActive = initActive.TranslateTo(_view.TextSnapshot, PointTrackingMode.Negative); _view.Selection.Select(newAnchor, newActive); _view.Caret.MoveTo(newActive, PositionAffinity.Predecessor); } }