in vsintegration/src/FSharp.LanguageService.Base/EditArray.cs [336:460]
void UpdateSelection(ArrayList edits) {
int lineDelta = 0;
int indexDelta = 0;
int currentLine = 0;
bool updateStart = true;
bool updateEnd = true;
bool selectionIsEmpty = TextSpanHelper.IsEmpty(this.selection);
foreach (EditSpan es in edits) {
TextSpan span = es.Span;
string text = es.Text;
int lastLine = currentLine;
int lastDelta = indexDelta;
if (currentLine != span.iStartLine) {
// We have moved to a new line, so the indexDelta is no longer relevant.
currentLine = span.iStartLine;
indexDelta = 0;
}
// Now adjust the span based on the current deltas.
span.iStartIndex += indexDelta;
if (currentLine == span.iEndLine) {
span.iEndIndex += indexDelta;
}
span.iStartLine += lineDelta;
span.iEndLine += lineDelta;
if (updateStart) {
TextSpan original = es.Span;
if (TextSpanHelper.ContainsInclusive(original, this.selection.iStartLine, this.selection.iStartIndex)) {
bool atEnd = (this.selection.iStartLine == original.iEndLine &&
this.selection.iStartIndex == original.iEndIndex);
this.selection.iStartLine = span.iStartLine;
this.selection.iStartIndex = span.iStartIndex;
if (atEnd){
// Selection was positioned at the end of the span, so
// skip past the inserted text to approximate that location.
if (es.LineCount > 0) {
this.selection.iStartLine += es.LineCount;
this.selection.iStartIndex = es.LengthOfLastLine;
} else {
this.selection.iStartIndex += es.LengthOfLastLine;
}
}
updateStart = false; // done
} else if (TextSpanHelper.StartsAfterStartOf(original, this.selection)) {
if (this.selection.iStartLine == lastLine) {
this.selection.iStartIndex += lastDelta;
}
this.selection.iStartLine += lineDelta;
updateStart = false; // done.
}
if (!updateStart && selectionIsEmpty) {
this.selection.iEndLine = this.selection.iStartLine;
this.selection.iEndIndex = this.selection.iStartIndex;
updateEnd = false; // done
}
}
if (updateEnd) {
TextSpan original = es.Span;
if (TextSpanHelper.StartsAfterEndOf(original, this.selection)) {
if (this.selection.iEndLine == lastLine) {
this.selection.iEndIndex += lastDelta;
}
this.selection.iEndLine += lineDelta;
updateEnd = false; // done.
} else if (TextSpanHelper.ContainsInclusive(original, this.selection.iEndLine, this.selection.iEndIndex)) {
this.selection.iEndLine = span.iStartLine;
this.selection.iEndIndex = span.iStartIndex;
// Now include the text we are inserting in the selection
if (es.LineCount > 0) {
this.selection.iEndLine += es.LineCount;
this.selection.iEndIndex = es.LengthOfLastLine;
} else {
this.selection.iEndIndex += es.LengthOfLastLine;
}
updateEnd = false; // done.
}
}
// Now adjust the deltas based on whether we just deleted anything.
if (span.iStartLine != span.iEndLine) {
// We are deleting one or more lines.
lineDelta += (span.iStartLine - span.iEndLine);
indexDelta = -span.iEndIndex;
currentLine = span.iStartLine;
} else if (span.iStartIndex != span.iEndIndex) {
indexDelta += (span.iStartIndex - span.iEndIndex);
}
// Now adjust the deltas based on what we just inserted
if (!string.IsNullOrEmpty(text)) {
lineDelta += es.LineCount;
if (span.iStartLine != span.iEndLine) { // we removed multiple lines
if (es.LineCount == 0) { // but we are not inserting any new lines
// Then we are appending to this line.
indexDelta = span.iStartIndex + es.LengthOfLastLine;
} else {
indexDelta = es.LengthOfLastLine; // otherwise we just started a new line.
}
} else if (es.LineCount != 0) { // we inserted new lines
// then calculate delta between new position versus position on original line.
indexDelta += es.LengthOfLastLine - span.iStartIndex;
} else {
indexDelta += es.LengthOfLastLine; // then delta is simply what we just inserted
}
}
}
if (updateStart) {
// Then start of selection is off the end of the list of edits.
if (this.selection.iStartLine == currentLine) {
this.selection.iStartIndex += indexDelta;
}
this.selection.iStartLine += lineDelta;
}
if (updateEnd) {
// Then end of selection is off the end of the list of edits.
if (this.selection.iEndLine == currentLine) {
this.selection.iEndIndex += indexDelta;
}
this.selection.iEndLine += lineDelta;
}
}