void UpdateSelection()

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;
            }
        }