Пример #1
0
        private bool IsEscapedPipeTyped(string currentText, SnapshotPoint positionBufferPosition)
        {
            positionBufferPosition = positionBufferPosition.Subtract(1);
            int backslashCount = 0;

            while (positionBufferPosition.Position > 0)
            {
                positionBufferPosition = positionBufferPosition.Subtract(1);
                if (positionBufferPosition.GetChar() != '\\')
                {
                    break;
                }
                backslashCount++;
            }
            return(backslashCount % 2 == 1);
        }
        /// <summary>
        ///     Convert the <see cref="SnapshotPoint"/> to a (0-based) line and column number.
        /// </summary>
        /// <param name="snapshotPoint">
        ///     The <see cref="SnapshotPoint"/>.
        /// </param>
        /// <returns>
        ///     The line and column number.
        /// </returns>
        public static (int line, int column) ToLineAndColumn(this SnapshotPoint snapshotPoint)
        {
            var line         = snapshotPoint.GetContainingLine();
            int lineNumber   = line.LineNumber;
            int columnNumber = snapshotPoint.Subtract(line.Start).Position;

            return(lineNumber, columnNumber);
        }
Пример #3
0
            public void PreOverType(out bool handledCommand)
            {
                handledCommand = false;
                if (ClosingPoint == null)
                {
                    return;
                }

                // Brace completion is not cancellable.
                var cancellationToken = CancellationToken.None;
                var snapshot          = this.SubjectBuffer.CurrentSnapshot;
                var document          = snapshot.GetOpenDocumentInCurrentContextWithChanges();

                SnapshotPoint closingSnapshotPoint = ClosingPoint.GetPoint(snapshot);

                if (!HasForwardTyping && _session.AllowOverType(this, cancellationToken))
                {
                    SnapshotPoint?caretPos = this.GetCaretPosition();

                    Debug.Assert(caretPos.HasValue && caretPos.Value.Position < closingSnapshotPoint.Position);

                    // ensure that we are within the session before clearing
                    if (caretPos.HasValue && caretPos.Value.Position < closingSnapshotPoint.Position && closingSnapshotPoint.Position > 0)
                    {
                        using (ITextUndoTransaction undo = CreateUndoTransaction())
                        {
                            _editorOperations.AddBeforeTextBufferChangePrimitive();

                            SnapshotSpan span = new SnapshotSpan(caretPos.Value, closingSnapshotPoint.Subtract(1));

                            using (ITextEdit edit = SubjectBuffer.CreateEdit())
                            {
                                edit.Delete(span);

                                if (edit.HasFailedChanges)
                                {
                                    Debug.Fail("Unable to clear closing brace");
                                    edit.Cancel();
                                    undo.Cancel();
                                }
                                else
                                {
                                    handledCommand = true;

                                    edit.Apply();

                                    MoveCaretToClosingPoint();

                                    _editorOperations.AddAfterTextBufferChangePrimitive();

                                    undo.Complete();
                                }
                            }
                        }
                    }
                }
            }
        /// <summary>
        /// Provide CompletionContext items for the current auto-completion session.
        /// </summary>
        /// <param name="session">The current auto-completion session.</param>
        /// <param name="trigger">The action that triggered the auto-completion session.</param>
        /// <param name="triggerLocation">The location in the text where auto-completion was triggered.</param>
        /// <param name="applicableToSpan">The text area that may be affected by the auto-completion.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <returns>A task returning a CompletionContext, filled with CompletionItems, if applicable.</returns>
        public Task <CompletionContext> GetCompletionContextAsync(InitialTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token) => Task.Run(() =>
        {
            IAsyncCompletionSession session = null;             // TODO: where to get from?
            bool addPrefix = false;
            if (trigger.Character == '\0' && !_navigator.GetExtentOfWord(triggerLocation.Subtract(1)).Span.GetText().EndsWith("<", System.StringComparison.OrdinalIgnoreCase))
            {
                // Meaning: autocomplete was not triggered by typing '<', but by using a shortcut, e.g. Ctrl+Space.
                // If the previous character is not '<', then we need to add one to the completion item text.
                addPrefix = true;
            }

            SnapshotSpan ats = applicableToSpan;
            SnapshotPoint t  = triggerLocation;
            // TODO: Find a way to determine where in the comment section the completion was triggered, to filter out CompletionItems that are not applicable in the current context

            List <CompletionItem> completions = new List <CompletionItem>()
            {
                CreateCompletionItem(addPrefix, "conceptualLink", "conceptualLink target=\"\"/>", "This element is used to create a link to a MAML topic within the See Also section of a topic or an inline link to a MAML topic within one of the other XML comments elements.", false, 3),
                CreateCompletionItem(addPrefix, "inheritdoc", "inheritdoc/>", "This element can help minimize the effort required to document complex APIs by allowing common documentation to be inherited from base types/members."),
                CreateCompletionItem(addPrefix, "inheritdocCref", "inheritdoc cref=\"\"/>", "Inherit documentation from a specific member.", false, 3),
                CreateCompletionItem(addPrefix, "inheritdocCrefSelect", "inheritdoc cref=\"\" select=\"summary|remarks\"/>", "Inherit documentation from a specific member and comments.", false, 28),
                CreateCompletionItem(addPrefix, "token", "token", "This element represents a replaceable tag within a topic."),
                // exception
                CreateCompletionItem(addPrefix, "AttachedEventComments", "AttachedEventComments", "This element is used to define the content that should appear on the auto-generated attached event member topic for a given WPF routed event member."),
                CreateCompletionItem(addPrefix, "AttachedPropertyComments", "AttachedPropertyComments", "This element is used to define the content that should appear on the auto-generated attached property member topic for a given WPF dependency property member."),
                CreateCompletionItem(addPrefix, "event", "event cref=\"\"", "This element is used to list events that can be raised by a type's member.", false, 1),
                CreateCompletionItem(addPrefix, "overloads", "overloads", "This element is used to define the content that should appear on the auto-generated overloads topic for a given set of member overloads."),
                CreateCompletionItem(addPrefix, "preliminary", "preliminary/>", "This element is used to indicate that a particular type or member is preliminary and is subject to change."),
                CreateCompletionItem(addPrefix, "threadsafety", "threadsafety static=\"true\" instance=\"false\"/>", "This element is used to indicate whether or not a class or structure's static and instance members are safe for use in multi-threaded scenarios."),
                // list
                CreateCompletionItem(addPrefix, "note", "note type=\"note\"", "This element is used to create a note-like section within a topic to draw attention to some important information."),
                // language
                CreateCompletionItem(addPrefix, "null", "see langword=\"null\"/>", "Inserts the language-specific keyword 'null'.", true),
                CreateCompletionItem(addPrefix, "static", "see langword=\"static\"/>", "Inserts the language-specific keyword 'static'.", true),
                CreateCompletionItem(addPrefix, "virtual", "see langword=\"virtual\"/>", "Inserts the language-specific keyword 'virtual'.", true),
                CreateCompletionItem(addPrefix, "true", "see langword=\"true\"/>", "Inserts the language-specific keyword 'true'.", true),
                CreateCompletionItem(addPrefix, "false", "see langword=\"false\"/>", "Inserts the language-specific keyword 'false'.", true),
                CreateCompletionItem(addPrefix, "abstract", "see langword=\"abstract\"/>", "Inserts the language-specific keyword 'abstract'.", true),
                CreateCompletionItem(addPrefix, "sealed", "see langword=\"sealed\"/>", "Inserts the language-specific keyword 'sealed'.", true),
                CreateCompletionItem(addPrefix, "async", "see langword=\"async\"/>", "Inserts the language-specific keyword 'async'.", true),
                CreateCompletionItem(addPrefix, "await", "see langword=\"await\"/>", "Inserts the language-specific keyword 'await'.", true),
                CreateCompletionItem(addPrefix, "asyncAwait", "see langword=\"async/await\"/>", "Inserts the language-specific keyword 'async/await'.", true),
                // code
                CreateCompletionItem(addPrefix, "codeImport", "code language=\"\" title=\" \" source=\"..\\Path\\SourceFile.cs\" region=\"Region Name\"/>", "This element is used to indicate that a multi-line section of text should be imported from the named region of the named file and formatted as a code block.", false, 65),
                CreateCompletionItem(addPrefix, "codeLanguage", "code language=\"\" title=\" \"></code>", "This element is used to indicate that a multi-line section of text should be formatted as a code block.", false, 19),
            };

            // Add handler for the completion of the session, so we can move the cursor to a position in the inserted text, if necessary.
            if (session != null)
            {
                session.ItemCommitted += Session_ItemCommitted;
            }

            return(new CompletionContext(completions.OrderBy(ci => ci.SortText).ToImmutableArray()));            // Why doesn't VS sort?
        });
        // basic checks to avoid incorrect behavior such as char c = '\'''
        private static bool AllowDefaultSession(SnapshotPoint openingPoint, char openingBrace, char closingBrace)
        {
            // avoid opening a new session next to the same char
            if (openingBrace == closingBrace && openingPoint.Position > 0)
            {
                char prevChar = openingPoint.Subtract(1).GetChar();
                if (openingBrace.Equals(prevChar))
                {
                    return(false);
                }
            }

            return(true);
        }
Пример #6
0
        public void PreOverType(out bool handledCommand)
        {
            handledCommand = false;

            // AllowOverType may make changes to the buffer such as for completing intellisense
            if (!HasForwardTyping && (_context == null || _context.AllowOverType(this)))
            {
                SnapshotPoint?caretPos             = CaretPosition;
                SnapshotPoint closingSnapshotPoint = _closingPoint.GetPoint(SubjectBuffer.CurrentSnapshot);

                Debug.Assert(caretPos.HasValue && caretPos.Value.Position < closingSnapshotPoint.Position);

                // ensure that we are within the session before clearing
                if (caretPos.HasValue && caretPos.Value.Position < closingSnapshotPoint.Position && closingSnapshotPoint.Position > 0)
                {
                    using (ITextUndoTransaction undo = CreateUndoTransaction())
                    {
                        _editorOperations.AddBeforeTextBufferChangePrimitive();

                        SnapshotSpan span = new SnapshotSpan(caretPos.Value, closingSnapshotPoint.Subtract(1));

                        using (ITextEdit edit = _subjectBuffer.CreateEdit())
                        {
                            edit.Delete(span);

                            if (edit.HasFailedChanges)
                            {
                                Debug.Fail("Unable to clear closing brace");
                                edit.Cancel();
                                undo.Cancel();
                            }
                            else
                            {
                                handledCommand = true;

                                edit.Apply();

                                MoveCaretToClosingPoint();

                                _editorOperations.AddAfterTextBufferChangePrimitive();

                                undo.Complete();
                            }
                        }
                    }
                }
            }
        }
Пример #7
0
        private async Task <RazorLanguageKind?> GetTriggerCharacterLanguageKindAsync(LSPDocumentSnapshot documentSnapshot, Position positionAfterTriggerChar, string triggerCharacter, CancellationToken cancellationToken)
        {
            // request.Character will point to the position after the character that was inserted.
            // For onTypeFormatting, it makes more sense to look up the projection of the character that was inserted.
            var line     = documentSnapshot.Snapshot.GetLineFromLineNumber(positionAfterTriggerChar.Line);
            var position = line.Start.Position + positionAfterTriggerChar.Character;
            var point    = new SnapshotPoint(documentSnapshot.Snapshot, position);

            // Subtract the trigger character length to go back to the position of the trigger character
            var triggerCharacterPoint = point.Subtract(triggerCharacter.Length);

            var triggerCharacterLine     = documentSnapshot.Snapshot.GetLineFromPosition(triggerCharacterPoint.Position);
            var triggerCharacterPosition = new Position(triggerCharacterLine.LineNumber, triggerCharacterPoint.Position - triggerCharacterLine.Start.Position);

            var triggerCharacterProjectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, triggerCharacterPosition, cancellationToken).ConfigureAwait(false);

            return(triggerCharacterProjectionResult?.LanguageKind);
        }
Пример #8
0
        private bool IsSessionValid(IBraceCompletionSession session)
        {
            bool isValid = false;

            _guardedOperations.CallExtensionPoint(() => {
                if (session.ClosingPoint != null && session.OpeningPoint != null && session.SubjectBuffer != null)
                {
                    ITextSnapshot snapshot             = session.SubjectBuffer.CurrentSnapshot;
                    SnapshotPoint closingSnapshotPoint = session.ClosingPoint.GetPoint(snapshot);
                    SnapshotPoint openingSnapshotPoint = session.OpeningPoint.GetPoint(snapshot);

                    // Verify that the closing and opening points still match the expected braces
                    isValid = closingSnapshotPoint.Position > 1 &&
                              openingSnapshotPoint.Position <= (closingSnapshotPoint.Position - 2) &&
                              openingSnapshotPoint.GetChar() == session.OpeningBrace &&
                              closingSnapshotPoint.Subtract(1).GetChar() == session.ClosingBrace;
                }
            });

            return(isValid);
        }
Пример #9
0
            private void Start(CancellationToken cancellationToken)
            {
                // this is where the caret should go after the change
                SnapshotPoint  pos = TextView.Caret.Position.BufferPosition;
                ITrackingPoint beforeTrackingPoint = pos.Snapshot.CreateTrackingPoint(pos.Position, PointTrackingMode.Negative);

                ITextSnapshot snapshot             = SubjectBuffer.CurrentSnapshot;
                SnapshotPoint closingSnapshotPoint = ClosingPoint.GetPoint(snapshot);

                if (closingSnapshotPoint.Position < 1)
                {
                    Debug.Fail("The closing point was not found at the expected position.");
                    EndSession();
                    return;
                }

                SnapshotPoint openingSnapshotPoint = closingSnapshotPoint.Subtract(1);

                if (openingSnapshotPoint.GetChar() != OpeningBrace)
                {
                    // there is a bug in editor brace completion engine on projection buffer that already fixed in vs_pro. until that is FIed to use
                    // I will make this not to assert
                    // Debug.Fail("The opening brace was not found at the expected position.");
                    EndSession();
                    return;
                }

                OpeningPoint = snapshot.CreateTrackingPoint(openingSnapshotPoint, PointTrackingMode.Positive);
                var document = snapshot.GetOpenDocumentInCurrentContextWithChanges();

                if (!_session.CheckOpeningPoint(this, cancellationToken))
                {
                    EndSession();
                    return;
                }

                using (ITextUndoTransaction undo = CreateUndoTransaction())
                {
                    // insert the closing brace
                    using (ITextEdit edit = SubjectBuffer.CreateEdit())
                    {
                        edit.Insert(closingSnapshotPoint, ClosingBrace.ToString());

                        if (edit.HasFailedChanges)
                        {
                            Debug.Fail("Unable to insert closing brace");

                            // exit without setting the closing point which will take us off the stack
                            edit.Cancel();
                            undo.Cancel();
                            return;
                        }
                        else
                        {
                            snapshot = edit.Apply();
                        }
                    }

                    SnapshotPoint beforePoint = beforeTrackingPoint.GetPoint(TextView.TextSnapshot);

                    // switch from positive to negative tracking so it stays against the closing brace
                    ClosingPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(ClosingPoint.GetPoint(snapshot), PointTrackingMode.Negative);

                    Debug.Assert(ClosingPoint.GetPoint(snapshot).Position > 0 && (new SnapshotSpan(ClosingPoint.GetPoint(snapshot).Subtract(1), 1))
                                 .GetText().Equals(ClosingBrace.ToString()), "The closing point does not match the closing brace character");

                    // move the caret back between the braces
                    TextView.Caret.MoveTo(beforePoint);

                    _session.AfterStart(this, cancellationToken);

                    undo.Complete();
                }
            }
Пример #10
0
            public void PostReturn()
            {
                if (this.GetCaretPosition().HasValue)
                {
                    SnapshotPoint closingSnapshotPoint = ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot);

                    if (closingSnapshotPoint.Position > 0 && HasNoForwardTyping(this.GetCaretPosition().Value, closingSnapshotPoint.Subtract(1)))
                    {
                        _session.AfterReturn(this, CancellationToken.None);
                    }
                }
            }
Пример #11
0
        public void Start()
        {
            // this is where the caret should go after the change
            SnapshotPoint  pos = _textView.Caret.Position.BufferPosition;
            ITrackingPoint beforeTrackingPoint = pos.Snapshot.CreateTrackingPoint(pos.Position, PointTrackingMode.Negative);

            ITextSnapshot snapshot             = _subjectBuffer.CurrentSnapshot;
            SnapshotPoint closingSnapshotPoint = _closingPoint.GetPoint(snapshot);

            if (closingSnapshotPoint.Position < 1)
            {
                Debug.Fail("The closing point was not found at the expected position.");
                EndSession();
                return;
            }

            SnapshotPoint openingSnapshotPoint = closingSnapshotPoint.Subtract(1);

            if (openingSnapshotPoint.GetChar() != OpeningBrace)
            {
                Debug.Fail("The opening brace was not found at the expected position.");
                EndSession();
                return;
            }

            _openingPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(openingSnapshotPoint, PointTrackingMode.Positive);

            using (ITextUndoTransaction undo = CreateUndoTransaction())
            {
                // insert the closing brace
                using (ITextEdit edit = _subjectBuffer.CreateEdit())
                {
                    edit.Insert(closingSnapshotPoint, _closingBrace.ToString(CultureInfo.CurrentCulture));

                    if (edit.HasFailedChanges)
                    {
                        Debug.Fail("Unable to insert closing brace");

                        // exit without setting the closing point which will take us off the stack
                        edit.Cancel();
                        undo.Cancel();
                        return;
                    }
                    else
                    {
                        snapshot = edit.Apply();
                    }
                }

                SnapshotPoint beforePoint = beforeTrackingPoint.GetPoint(_textView.TextSnapshot);

                // switch from positive to negative tracking so it stays against the closing brace
                _closingPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(_closingPoint.GetPoint(snapshot), PointTrackingMode.Negative);

                Debug.Assert(_closingPoint.GetPoint(snapshot).Position > 0 && (new SnapshotSpan(_closingPoint.GetPoint(snapshot).Subtract(1), 1))
                             .GetText().Equals(_closingBrace.ToString(CultureInfo.CurrentCulture), System.StringComparison.Ordinal), "The closing point does not match the closing brace character");

                // move the caret back between the braces
                _textView.Caret.MoveTo(beforePoint);

                if (_context != null)
                {
                    // allow the context to do extra formatting
                    _context.Start(this);
                }

                undo.Complete();
            }
        }
Пример #12
0
        public void PostReturn()
        {
            if (_context != null && CaretPosition.HasValue)
            {
                SnapshotPoint closingSnapshotPoint = _closingPoint.GetPoint(SubjectBuffer.CurrentSnapshot);

                if (closingSnapshotPoint.Position > 0 && HasNoForwardTyping(CaretPosition.Value, closingSnapshotPoint.Subtract(1)))
                {
                    _context.OnReturn(this);
                }
            }
        }