Example #1
0
        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.GetWordExtent"]/*' />
        /// <summary>Returns the result of Source.GetWordExtent.</summary>
        public virtual int GetWordExtent(int line, int index, uint flags, TextSpan[] span)
        {
            Debug.Assert(line >= 0 && index >= 0);
            if (span == null)
            {
                NativeHelpers.RaiseComError(NativeMethods.E_INVALIDARG);
            }
            else
            {
                span[0] = new TextSpan();
            }

            span[0].iStartLine  = span[0].iEndLine = line;
            span[0].iStartIndex = span[0].iEndIndex = index;

            int start, end;

            if (!this.source.GetWordExtent(line, index, (WORDEXTFLAGS)flags, out start, out end))
            {
                return(NativeMethods.S_FALSE);
            }

            span[0].iStartIndex = start;
            span[0].iEndIndex   = end;
            TextSpanHelper.MakePositive(ref span[0]);
            return(NativeMethods.S_OK);
        }
Example #2
0
        /// <include file='doc\ExpansionProvider.uex' path='docs/doc[@for="ExpansionProvider.InsertSpecificExpansion"]/*' />
        public virtual bool InsertSpecificExpansion(IVsTextView view, XmlElement snippet, TextSpan pos, string relativePath)
        {
            if (this.expansionActive)
            {
                this.EndTemplateEditing(true);
            }

            if (this.source.IsCompletorActive)
            {
                this.source.DismissCompletor();
            }

            this.view = view;
            MSXML.IXMLDOMDocument doc = new MSXML.DOMDocumentClass();
            if (!doc.loadXML(snippet.OuterXml))
            {
                throw new ArgumentException(doc.parseError.reason);
            }
            Guid guidLanguage = this.source.LanguageService.GetLanguageServiceGuid();

            TextSpan2 t2 = TextSpanHelper.TextSpan2FromTextSpan(pos);
            int       hr = this.vsExpansion.InsertSpecificExpansion(doc, t2, this, guidLanguage, relativePath, out this.expansionSession);

            if (hr != NativeMethods.S_OK || this.expansionSession == null)
            {
                this.EndTemplateEditing(true);
            }
            else
            {
                this.expansionActive = true;
                return(true);
            }
            return(false);
        }
Example #3
0
        /// <include file='doc\ExpansionProvider.uex' path='docs/doc[@for="ExpansionProvider.FormatSpan"]/*' />
        public virtual int FormatSpan(IVsTextLines buffer, TextSpan2[] ts)
        {
            if (this.source.GetTextLines() != buffer)
            {
                throw new System.ArgumentException(SR.GetString(SR.UnknownBuffer), "buffer");
            }
            int rc = NativeMethods.E_NOTIMPL;

            if (ts != null)
            {
                for (int i = 0, n = ts.Length; i < n; i++)
                {
                    if (this.source.LanguageService.Preferences.EnableFormatSelection)
                    {
                        TextSpan span = TextSpanHelper.TextSpanFromTextSpan2(ts[i]);
                        // We should not merge edits in this case because it might clobber the
                        // $varname$ spans which are markers for yellow boxes.
                        EditArray edits = new EditArray(this.source, this.view, false, SR.GetString(SR.FormatSpan));
                        this.source.ReformatSpan(edits, span);
                        edits.ApplyEdits();
                        rc = NativeMethods.S_OK;
                    }
                }
            }
            return(rc);
        }
Example #4
0
        /// <include file='doc\ExpansionProvider.uex' path='docs/doc[@for="ExpansionProvider.InsertNamedExpansion"]/*' />
        public virtual bool InsertNamedExpansion(IVsTextView view, string title, string path, TextSpan pos, bool showDisambiguationUI)
        {
            if (this.source.IsCompletorActive)
            {
                this.source.DismissCompletor();
            }

            this.view = view;
            if (this.expansionActive)
            {
                this.EndTemplateEditing(true);
            }
            TextSpan2 t2           = TextSpanHelper.TextSpan2FromTextSpan(pos);
            Guid      guidLanguage = this.source.LanguageService.GetLanguageServiceGuid();

            int hr = this.vsExpansion.InsertNamedExpansion(title, path, t2, this, guidLanguage, showDisambiguationUI ? 1 : 0, out this.expansionSession);

            if (hr != NativeMethods.S_OK || this.expansionSession == null)
            {
                this.EndTemplateEditing(true);
                return(false);
            }
            else if (hr == NativeMethods.S_OK)
            {
                this.expansionActive = true;
                return(true);
            }
            return(false);
        }
Example #5
0
        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.HandleGoto"]/*' />
        /// <summary>Handles VsCommands.GotoDefn, VsCommands.GotoDecl and VsCommands.GotoRef by
        /// calling OnSyncGoto on the Source object and opening the text editor on the resulting
        /// URL, then scrolling to the resulting span.</summary>
        public virtual void HandleGoto(VsCommands cmd)
        {
            TextSpan ts = new TextSpan();

            // Get the caret position
            NativeMethods.ThrowOnFailure(this.textView.GetCaretPos(out ts.iStartLine, out ts.iStartIndex));
            ts.iEndLine  = ts.iStartLine;
            ts.iEndIndex = ts.iStartIndex;

            // Get the tip text at that location.
            // Wait, since the user specifically requested this one...
            TextSpan span;
            string   url = this.source.OnSyncGoto(cmd, this.textView, ts.iEndLine, ts.iEndIndex, out span);

            if (url == null || url.Trim().Length == 0)   // nothing to show
            {
                return;
            }

            // Open the referenced document, and scroll to the given location.
            IVsUIHierarchy hierarchy;
            uint           itemID;
            IVsWindowFrame frame;
            IVsTextView    view;

            VsShell.OpenDocument(this.service.Site, url, NativeMethods.LOGVIEWID_Code, out hierarchy, out itemID, out frame, out view);
            if (view != null)
            {
                TextSpanHelper.MakePositive(ref span);
                NativeMethods.ThrowOnFailure(view.EnsureSpanVisible(span));
                NativeMethods.ThrowOnFailure(view.SetSelection(span.iStartLine, span.iStartIndex, span.iEndLine, span.iEndIndex));
            }
        }
Example #6
0
        /// <include file='doc\DocumentTask.uex' path='docs/doc[@for="DocumentTask.OnNavigate"]/*' />
        protected override void OnNavigate(EventArgs e)
        {
            TextSpan span = this.span;

            if (textLineMarker != null)
            {
                TextSpan[] spanArray = new TextSpan[1];
                NativeMethods.ThrowOnFailure(textLineMarker.GetCurrentSpan(spanArray));
                span = spanArray[0];
            }

            IVsUIHierarchy hierarchy;
            uint           itemID;
            IVsWindowFrame docFrame;
            IVsTextView    textView;

            VsShell.OpenDocument(this.site, this.fileName, NativeMethods.LOGVIEWID_Code, out hierarchy, out itemID, out docFrame, out textView);
            NativeMethods.ThrowOnFailure(docFrame.Show());
            if (textView != null)
            {
                NativeMethods.ThrowOnFailure(textView.SetCaretPos(span.iStartLine, span.iStartIndex));
                TextSpanHelper.MakePositive(ref span);
                NativeMethods.ThrowOnFailure(textView.SetSelection(span.iStartLine, span.iStartIndex, span.iEndLine, span.iEndIndex));
                NativeMethods.ThrowOnFailure(textView.EnsureSpanVisible(span));
            }
            base.OnNavigate(e);
        }
Example #7
0
        /// <include file='doc\EditArray.uex' path='docs/doc[@for="EditArray.Add"]/*' />
        /// <summary>
        /// Add a new atomic edit to the array.  The edits cannot intersect each other.
        /// The spans in each edit must be based on the current state of the buffer,
        /// and not based on post-edit spans.  This EditArray will calculate the
        /// post edit spans for you.
        /// </summary>
        /// <param name="editSpan"></param>
        public void Add(EditSpan editSpan)
        {
            if (editSpan == null)
            {
                throw new ArgumentNullException("editSpan");
            }

            for (int i = this.editList.Count - 1; i >= 0; i--)
            {
                EditSpan e = (EditSpan)this.editList[i];
                if (TextSpanHelper.Intersects(editSpan.Span, e.Span))
                {
                    string msg = SR.GetString(SR.EditIntersects, i);
#if LANGTRACE
                    Debug.Assert(false, msg);
                    TraceEdits();
#endif
                    throw new System.ArgumentException(msg);
                }
                if (TextSpanHelper.StartsAfterStartOf(editSpan.Span, e.Span))
                {
                    this.editList.Insert(i + 1, editSpan);
                    return;
                }
            }
            this.editList.Insert(0, editSpan);
        }
Example #8
0
        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.GetFullDataTipText"]/*' />
        /// <summary>This method checks to see if the IVsDebugger is running, and if so,
        /// calls it to get additional information about the current token and returns a combined result.
        /// You can return an HRESULT here like TipSuccesses2.TIP_S_NODEFAULTTIP.</summary>
        public virtual int GetFullDataTipText(string textValue, TextSpan ts, out string fullTipText)
        {
            IVsTextLines textLines;

            fullTipText = textValue;

            NativeMethods.ThrowOnFailure(this.textView.GetBuffer(out textLines));

            // Now, check if the debugger is running and has anything to offer
            try {
                Microsoft.VisualStudio.Shell.Interop.IVsDebugger debugger = this.service.GetIVsDebugger();
                if (debugger != null && this.mgr.LanguageService.IsDebugging)
                {
                    TextSpan[] tsdeb = new TextSpan[1] {
                        new TextSpan()
                    };
                    if (!TextSpanHelper.IsEmpty(ts))
                    {
                        // While debugging we always want to evaluate the expression user is hovering over
                        NativeMethods.ThrowOnFailure(textView.GetWordExtent(ts.iStartLine, ts.iStartIndex, (uint)WORDEXTFLAGS.WORDEXT_FINDEXPRESSION, tsdeb));
                        // If it failed to find something, then it means their is no expression so return S_FALSE
                        if (TextSpanHelper.IsEmpty(tsdeb[0]))
                        {
                            return(NativeMethods.S_FALSE);
                        }
                    }
                    string debugTextTip = null;
                    int    hr           = debugger.GetDataTipValue(textLines, tsdeb, null, out debugTextTip);
                    fullTipText = debugTextTip;
                    if (hr == (int)TipSuccesses2.TIP_S_NODEFAULTTIP)
                    {
                        return(hr);
                    }
                    if (!string.IsNullOrEmpty(debugTextTip) && debugTextTip != textValue)
                    {
                        // The debugger in this case returns "=value [type]" which we can
                        // append to the variable name so we get "x=value[type]" as the full tip.
                        int i = debugTextTip.IndexOf('=');
                        if (i >= 0)
                        {
                            string spacer = (i < debugTextTip.Length - 1 && debugTextTip[i + 1] == ' ') ? " " : "";
                            fullTipText = textValue + spacer + debugTextTip.Substring(i);
                        }
                    }
                }
#if DEBUG
            } catch (COMException e) {
                Trace.WriteLine("COMException: GetDataTipValue, errorcode=" + e.ErrorCode);
#else
            } catch (COMException) {
#endif
            }
            if (string.IsNullOrEmpty(fullTipText))
            {
                fullTipText = textValue;
            }
            return(NativeMethods.S_OK);
        }
Example #9
0
 /// <include file='doc\EditArray.uex' path='docs/doc[@for="EditSpan.EditSpan"]/*' />
 /// <summary>
 /// Construct a new edit span object
 /// </summary>
 /// <param name="toReplace">The text span to remove from the buffer (can be empty)</param>
 /// <param name="insertText">The text to insert in it's place (can be null)</param>
 public EditSpan(TextSpan toReplace, string insertText)
 {
     if (!TextSpanHelper.IsPositive(toReplace))
     {
         TextSpanHelper.MakePositive(ref toReplace);
     }
     this.span      = toReplace;
     this.text      = insertText;
     this.lineCount = -1;
 }
Example #10
0
 /// <include file='doc\Source.uex' path='docs/doc[@for="ViewFilter.GetSelection"]/*' />
 /// <summary>Returns the current selection, adjusted to become a positive text span</summary>
 public TextSpan GetSelection()
 {
     //get text range
     TextSpan[] aspan = new TextSpan[1];
     NativeMethods.ThrowOnFailure(this.textView.GetSelectionSpan(aspan));
     if (!TextSpanHelper.IsPositive(aspan[0]))
     {
         TextSpanHelper.MakePositive(ref aspan[0]);
     }
     return(aspan[0]);
 }
Example #11
0
        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.GetPairExtents"]/*' />
        public virtual int GetPairExtents(int line, int index, TextSpan[] span)
        {
            Debug.Assert(line >= 0 && index >= 0);
            if (span == null)
            {
                return(NativeMethods.E_INVALIDARG);
            }

            this.source.GetPairExtents(this.textView, line, index, out span[0]);
            TextSpanHelper.MakePositive(ref span[0]);
            return(NativeMethods.S_OK);
        }
Example #12
0
        /// <include file='doc\ExpansionProvider.uex' path='docs/doc[@for="ExpansionProvider.InTemplateEditingMode"]/*' />
        public virtual TextSpan GetExpansionSpan()
        {
            if (this.expansionSession == null)
            {
                throw new System.InvalidOperationException(SR.GetString(SR.NoExpansionSession));
            }
            TextSpan2[] pts = new TextSpan2[1];
            int         hr  = this.expansionSession.GetSnippetSpan(pts);

            if (NativeMethods.Succeeded(hr))
            {
                return(TextSpanHelper.TextSpanFromTextSpan2(pts[0]));
            }
            return(new TextSpan());
        }
Example #13
0
        // This method simulates what VS does in debug mode so that we can catch the
        // errors in managed code before they go to the native debug assert.
        public static bool ValidSpan(Source src, TextSpan span)
        {
            if (!ValidCoord(src, span.iStartLine, span.iStartIndex))
            {
                return(false);
            }

            if (!ValidCoord(src, span.iEndLine, span.iEndIndex))
            {
                return(false);
            }

            // end must be >= start
            if (!TextSpanHelper.IsPositive(span))
            {
                return(false);
            }

            return(true);
        }
Example #14
0
 /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.ReformatSelection;"]/*' />
 public virtual void ReformatSelection()
 {
     if (this.CanReformat())
     {
         Debug.Assert(this.source != null);
         if (this.source != null)
         {
             TextSpan ts = GetSelection();
             if (TextSpanHelper.IsEmpty(ts))
             {
                 // format just this current line.
                 ts.iStartIndex = 0;
                 ts.iEndLine    = ts.iStartLine;
                 ts.iEndIndex   = this.source.GetLineLength(ts.iStartLine);
             }
             EditArray mgr = new EditArray(this.source, this.TextView, true, SR.GetString(SR.FormatSpan));
             this.source.ReformatSpan(mgr, ts);
             mgr.ApplyEdits();
         }
     }
 }
Example #15
0
        /// <include file='doc\ExpansionProvider.uex' path='docs/doc[@for="ExpansionProvider.FindExpansionByShortcut"]/*' />
        /// <summary>Returns S_OK if match found, S_FALSE if expansion UI is shown, and error otherwise</summary>
        public virtual int FindExpansionByShortcut(IVsTextView view, string shortcut, TextSpan span, bool showDisambiguationUI, out string title, out string path)
        {
            if (this.expansionActive)
            {
                this.EndTemplateEditing(true);
            }
            this.view = view;
            title     = path = null;

            LanguageService     svc = this.source.LanguageService;
            IVsExpansionManager mgr = svc.Site.GetService(typeof(SVsExpansionManager)) as IVsExpansionManager;

            if (mgr == null)
            {
                return(NativeMethods.E_FAIL);
            }
            Guid guidLanguage = svc.GetLanguageServiceGuid();

            TextSpan2[] pts = new TextSpan2[1];
            pts[0] = TextSpanHelper.TextSpan2FromTextSpan(span);
            int hr = mgr.GetExpansionByShortcut(this, guidLanguage, shortcut, this.TextView, pts, showDisambiguationUI ? 1 : 0, out path, out title);

            return(hr);
        }
Example #16
0
 public static bool Intersects(TextSpan span1, TextSpan span2)
 {
     return(TextSpanHelper.StartsBeforeEndOf(span1, span2) &&
            TextSpanHelper.EndsAfterStartOf(span1, span2));
 }
Example #17
0
 public static bool IsEmbedded(TextSpan span1, TextSpan span2)
 {
     return(!TextSpanHelper.IsSameSpan(span1, span2) &&
            TextSpanHelper.StartsAfterStartOf(span1, span2) &&
            TextSpanHelper.EndsBeforeEndOf(span1, span2));
 }
Example #18
0
        const int ChunkThreshold = 1000; // don't combine chunks separate by more than 1000 characters.

        ArrayList MergeEdits(ArrayList edits)
        {
            StringBuilder buffer    = new StringBuilder();
            EditSpan      combined  = null;
            ArrayList     merged    = new ArrayList();
            ArrayList     markers   = GetTextMarkers();
            int           markerPos = 0;
            TextSpan      marker    = (markers.Count > 0) ? (TextSpan)markers[0] : new TextSpan();

            foreach (EditSpan editSpan in edits)
            {
                TextSpan span = editSpan.Span;
                string   text = editSpan.Text;

                if (markerPos < markers.Count &&
                    (TextSpanHelper.StartsAfterStartOf(span, marker) || TextSpanHelper.EndsAfterStartOf(span, marker)))
                {
                    AddCombinedEdit(combined, buffer, merged);
                    if (TextSpanHelper.Intersects(span, marker))
                    {
                        combined = null;
                        // Have to apply this as a distinct edit operation.
                        merged.Add(editSpan);
                    }
                    else
                    {
                        combined = editSpan;
                        buffer.Append(text);
                    }
                    while (++markerPos < markers.Count)
                    {
                        marker = (TextSpan)markers[markerPos];
                        if (!TextSpanHelper.StartsAfterStartOf(span, marker) && !TextSpanHelper.EndsAfterStartOf(span, marker))
                        {
                            break;
                        }
                    }
                }
                else if (combined == null)
                {
                    combined = editSpan;
                    buffer.Append(text);
                }
                else
                {
                    // A little sanity check here, if there are too many characters in between the two
                    // edits, then keep them separate.
                    TextSpan s       = combined.Span;
                    string   between = this.source.GetText(s.iEndLine, s.iEndIndex, span.iStartLine, span.iStartIndex);
                    if (between.Length > ChunkThreshold)
                    {
                        AddCombinedEdit(combined, buffer, merged);
                        combined = editSpan;
                        buffer.Append(text);
                    }
                    else
                    {
                        // merge edit spans by adding the text in-between the current and previous spans.
                        buffer.Append(between);
                        buffer.Append(text); // and add the new text.
                        s.iEndIndex   = span.iEndIndex;
                        s.iEndLine    = span.iEndLine;
                        combined.Span = s;
                    }
                }
            }
            AddCombinedEdit(combined, buffer, merged);
            return(merged);
        }
Example #19
0
        /// <include file='doc\ExpansionProvider.uex' path='docs/doc[@for="ExpansionProvider.HandlePreExec"]/*' />
        public virtual bool HandlePreExec(ref Guid guidCmdGroup, uint nCmdId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
        {
            if (!this.expansionActive || this.expansionSession == null)
            {
                return(false);
            }

            this.completorActiveDuringPreExec = this.IsCompletorActive(this.view);

            if (guidCmdGroup == typeof(VsCommands2K).GUID)
            {
                VsCommands2K cmd = (VsCommands2K)nCmdId;
#if TRACE_EXEC
                Trace.WriteLine(String.Format("ExecCommand: {0}", cmd.ToString()));
#endif
                switch (cmd)
                {
                case VsCommands2K.CANCEL:
                    if (this.completorActiveDuringPreExec)
                    {
                        return(false);
                    }
                    EndTemplateEditing(true);
                    return(true);

                case VsCommands2K.RETURN:
                    bool leaveCaret = false;
                    int  line = 0, col = 0;
                    if (NativeMethods.Succeeded(this.view.GetCaretPos(out line, out col)))
                    {
                        TextSpan span = GetExpansionSpan();
                        if (!TextSpanHelper.ContainsExclusive(span, line, col))
                        {
                            leaveCaret = true;
                        }
                    }
                    if (this.completorActiveDuringPreExec)
                    {
                        return(false);
                    }
                    EndTemplateEditing(leaveCaret);
                    if (leaveCaret)
                    {
                        return(false);
                    }
                    return(true);

                case VsCommands2K.BACKTAB:
                    if (this.completorActiveDuringPreExec)
                    {
                        return(false);
                    }
                    this.expansionSession.GoToPreviousExpansionField();
                    return(true);

                case VsCommands2K.TAB:
                    if (this.completorActiveDuringPreExec)
                    {
                        return(false);
                    }
                    this.expansionSession.GoToNextExpansionField(0);     // fCommitIfLast=false
                    return(true);

#if TRACE_EXEC
                case VsCommands2K.TYPECHAR:
                    if (pvaIn != IntPtr.Zero)
                    {
                        Variant v  = Variant.ToVariant(pvaIn);
                        char    ch = v.ToChar();
                        Trace.WriteLine(String.Format("TYPECHAR: {0}, '{1}', {2}", cmd.ToString(), ch.ToString(), (int)ch));
                    }
                    return(true);
#endif
                }
            }
            return(false);
        }
Example #20
0
        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;
            }
        }