Пример #1
0
        /// <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>
        internal 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);
        }
Пример #2
0
 /// <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>
 internal EditSpan(TextSpan toReplace, string insertText)
 {
     if (!TextSpanHelper.IsPositive(toReplace))
     {
         TextSpanHelper.MakePositive(ref toReplace);
     }
     this.span      = toReplace;
     this.text      = insertText;
     this.lineCount = -1;
 }
Пример #3
0
        // It is important that this function not throw an exception.
        protected override void OnNavigate(EventArgs e)
        {
            try {
                TextSpan span = this.span;
                if (textLineMarker != null)
                {
                    TextSpan[] spanArray = new TextSpan[1];
                    if (NativeMethods.Failed(textLineMarker.GetCurrentSpan(spanArray)))
                    {
                        Debug.Assert(false, "Unexpected error getting current span in OnNavigate");
                        return;
                    }
                    span = spanArray[0];
                }

                IVsUIHierarchy hierarchy;
                uint           itemID;
                IVsWindowFrame docFrame;
                IVsTextView    textView;
                try {
                    VsShell.OpenDocument(this.site, this.fileName, NativeMethods.LOGVIEWID_Code, out hierarchy, out itemID, out docFrame, out textView);
                } catch (System.ArgumentException) {
                    // No assert here because this can legitimately happen when quickly doing F8 during a refresh of language service errors (see 4846)
                    return;
                }
                catch (System.IO.FileNotFoundException)
                {
                    // No assert here because this can legitimately happen, e.g. with type provider errors (which are attributed to "FSC" file), or other cases
                    return;
                }
                if (NativeMethods.Failed(docFrame.Show()))
                {
                    // No assert here because this can legitimately happen when quickly doing F8 during a refresh of language service errors (see 4846)
                    return;
                }
                if (textView != null)
                {
                    // In the off-chance these methods fail, we 'recover' by continuing. It is more helpful to show the user the file if possible than not.
                    textView.SetCaretPos(span.iStartLine, span.iStartIndex);
                    TextSpanHelper.MakePositive(ref span);
                    textView.SetSelection(span.iStartLine, span.iStartIndex, span.iEndLine, span.iEndIndex);
                    textView.EnsureSpanVisible(span);
                }
                base.OnNavigate(e);
            } catch (Exception exn) {
                System.Diagnostics.Debug.Assert(false, "Unexpected exception thrown from DocumentTask.OnNavigate" + exn.ToString() + exn.StackTrace);
            }
        }
Пример #4
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.
        internal static bool ValidSpan(ISource 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);
        }
Пример #5
0
 internal static bool Intersects(TextSpan span1, TextSpan span2)
 {
     return(TextSpanHelper.StartsBeforeEndOf(span1, span2) &&
            TextSpanHelper.EndsAfterStartOf(span1, span2));
 }
Пример #6
0
 //returns true is span1 is Embedded in span2
 internal static bool IsEmbedded(TextSpan span1, TextSpan span2)
 {
     return(!TextSpanHelper.IsSameSpan(span1, span2) &&
            TextSpanHelper.StartsAfterStartOf(span1, span2) &&
            TextSpanHelper.EndsBeforeEndOf(span1, span2));
 }
Пример #7
0
        internal 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);
                    }
                    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);
        }
Пример #8
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;
            }
        }
Пример #9
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.
                    int startOffset = source.GetPositionOfLineIndex(combined.Span.iEndLine, combined.Span.iEndIndex);
                    int endOffset   = source.GetPositionOfLineIndex(span.iStartLine, span.iStartIndex);
                    if (endOffset - startOffset > 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.
                        TextSpan s       = combined.Span;
                        string   between = this.source.GetText(s.iEndLine, s.iEndIndex, span.iStartLine, span.iStartIndex);
                        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);
        }