in src/Editor/Text/Impl/EditorOperations/EditorOperations.cs [3624:3798]
public bool InsertTextAsBox(string text, out VirtualSnapshotPoint boxStart, out VirtualSnapshotPoint boxEnd, string undoText)
{
if (text == null)
throw new ArgumentNullException(nameof(text));
boxStart = boxEnd = _textView.Caret.Position.VirtualBufferPosition;
// You can't use out parameters in a lambda or delegate, so just make a copy of
// boxStart/boxEnd
VirtualSnapshotPoint newStart, newEnd;
newStart = newEnd = boxStart;
if (text.Length == 0)
return this.InsertText(text);
Func<bool> action = () =>
{
// Separate edit transaction for the delete
if (!DeleteHelper(_textView.Selection.SelectedSpans))
return false;
// Put the selection in box mode for this operation
_textView.Selection.Mode = TextSelectionMode.Box;
_textView.Caret.MoveTo(_textView.Selection.Start);
// Remember the starting position
VirtualSnapshotPoint oldCaretPos = _textView.Caret.Position.VirtualBufferPosition;
double startX = _textView.Caret.Left;
// Estimate the number of spaces to the caret, to be used
// for any amount of text that goes past the end of the buffer
int spacesToCaret = _editorPrimitives.View.GetTextPoint(oldCaretPos.Position).DisplayColumn + oldCaretPos.VirtualSpaces;
ITrackingPoint endPoint = null;
int? firstLineInsertedVirtualSpaces = null;
using (ITextEdit textEdit = _editorPrimitives.Buffer.AdvancedTextBuffer.CreateEdit())
{
VirtualSnapshotPoint currentCaret = oldCaretPos;
ITextViewLine currentLine = _textView.GetTextViewLineContainingBufferPosition(currentCaret.Position);
bool pastEndOfBuffer = false;
// Read a line at a time from the given text, inserting each line of text
// into the buffer at a successive line below the line the caret is on.
// For any text left over at the end of the buffer, insert endlines as
// well (to create new lines at the end of the file), with virtual space
// for padding.
using (StringReader reader = new StringReader(text))
{
for (string lineText = reader.ReadLine(); lineText != null;)
{
if (lineText.Length > 0)
{
// Remember the endPoint, for determining the boxEnd argument
endPoint = _textView.TextSnapshot.CreateTrackingPoint(currentCaret.Position, PointTrackingMode.Positive);
int whitespaceLength = 0;
// Add on any virtual space needed
if (currentCaret.IsInVirtualSpace)
{
string whitespace = GetWhitespaceForVirtualSpace(currentCaret);
lineText = whitespace + lineText;
whitespaceLength = whitespace.Length;
}
// Update information about the first inserted line
if (!firstLineInsertedVirtualSpaces.HasValue)
{
firstLineInsertedVirtualSpaces = whitespaceLength;
oldCaretPos = currentCaret;
}
// Insert the text as part of this edit transaction
if (!textEdit.Insert(currentCaret.Position, lineText))
return false;
}
// We've already read past the end of the buffer, so we're done
if (pastEndOfBuffer)
break;
// If this is the last line in the file, collect the rest
// of the text to insert.
if (currentLine.LineBreakLength == 0)
{
string whitespace = GetWhitespaceForDisplayColumn(spacesToCaret);
string newline = _editorOptions.GetNewLineCharacter();
string extraLine = null;
lineText = string.Empty;
string blankLines = string.Empty;
while ((extraLine = reader.ReadLine()) != null)
{
// Either add the line (if there is any text), or
// just add the newline
if (extraLine.Length > 0)
{
lineText += blankLines + // Any blank lines
newline + // a line break, to get a new line
whitespace + // realized virtual space
extraLine; // the line text itself
blankLines = string.Empty;
}
else
{
blankLines += newline;
}
}
pastEndOfBuffer = true;
currentCaret = new VirtualSnapshotPoint(currentLine.EndIncludingLineBreak);
// Current line hasn't changed, so we don't need to set it again
}
else // Otherwise, try and read the next line
{
lineText = reader.ReadLine();
if (lineText != null)
{
currentLine = _textView.GetTextViewLineContainingBufferPosition(currentLine.EndIncludingLineBreak);
currentCaret = currentLine.GetInsertionBufferPositionFromXCoordinate(startX);
}
}
}
}
// If we didn't actually insert any text, then cancel the edit and return false
if (endPoint == null)
{
textEdit.Cancel();
return false;
}
textEdit.Apply();
if (textEdit.Canceled)
return false;
}
// Now, figure out the start and end positions
// and update the caret and selection.
_textView.Selection.Clear();
// Move the caret back to the starting point, which is now
// no longer in virtual space.
int virtualSpaces = firstLineInsertedVirtualSpaces.HasValue ? firstLineInsertedVirtualSpaces.Value : 0;
_textView.Caret.MoveTo(new SnapshotPoint(_textView.TextSnapshot,
oldCaretPos.Position.Position + virtualSpaces));
newStart = _textView.Caret.Position.VirtualBufferPosition;
// endPoint was a forward-tracking point at the beginning of the last insertion,
// so it should be positioned at the very end of the inserted text in the new
// snapshot.
newEnd = new VirtualSnapshotPoint(endPoint.GetPoint(_textView.TextSnapshot));
return true;
};
bool succeeded = ExecuteAction(undoText, action);
if (succeeded)
{
boxStart = newStart;
boxEnd = newEnd;
}
return succeeded;
}