Exemple #1
0
        private void StartSession(ITrackingPoint triggerPoint)
        {
            Log.Debug("Creating new completion session...");
            _broker.DismissAllSessions(_textView);
            _activeSession = _broker.CreateCompletionSession(_textView, triggerPoint, true);
            _activeSession.Properties.AddProperty(BufferProperties.SessionOriginIntellisense, "Intellisense");
            _activeSession.Dismissed += CompletionSession_Dismissed;
            _activeSession.Start();

            if (_startTabComplete == true)
            {
                var completions = _activeSession.SelectedCompletionSet.Completions;

                if (completions != null && completions.Count > 0)
                {
                    var startPoint = _activeSession.SelectedCompletionSet.ApplicableTo.GetStartPoint(_textView.TextBuffer.CurrentSnapshot).Position;
                    _tabCompleteSession = new TabCompleteSession(completions, _activeSession.SelectedCompletionSet.SelectionStatus, startPoint);
                    _activeSession.Commit();
                }

                _startTabComplete = false;
            }
        }
Exemple #2
0
        /// <summary>
        /// Main method used to determine how to handle keystrokes within a ITextBuffer.
        /// </summary>
        /// <param name="pguidCmdGroup">The GUID of the command group.</param>
        /// <param name="nCmdId">The command ID.</param>
        /// <param name="nCmdexecopt">
        ///    Specifies how the object should execute the command. Possible values are taken from the
        ///    Microsoft.VisualStudio.OLE.Interop.OLECMDEXECOPT and Microsoft.VisualStudio.OLE.Interop.OLECMDID_WINDOWSTATE_FLAG
        ///    enumerations.
        /// </param>
        /// <param name="pvaIn">The input arguments of the command.</param>
        /// <param name="pvaOut">The output arguments of the command.</param>
        /// <returns></returns>
        public int Exec(ref Guid pguidCmdGroup, uint nCmdId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
        {
            bool?isInStringArea = null;
            var  command        = (VSConstants.VSStd2KCmdID)nCmdId;

            if (VsShellUtilities.IsInAutomationFunction(_serviceProvider) ||
                IsUnhandledCommand(pguidCmdGroup, command) ||
                Utilities.IsCaretInCommentArea(_textView))
            {
                Log.DebugFormat("Non-VSStd2K command: '{0}'", ToCommandName(pguidCmdGroup, nCmdId));
                return(NextCommandHandler.Exec(ref pguidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut));
            }

            //make a copy of this so we can look at it after forwarding some commands
            var typedChar = char.MinValue;

            // Exit tab complete session if command is any recognized command other than tab
            if (_tabCompleteSession != null && command != VSConstants.VSStd2KCmdID.TAB && command != VSConstants.VSStd2KCmdID.BACKTAB)
            {
                _tabCompleteSession = null;
                _startTabComplete   = false;
            }

            //make sure the input is a char before getting it
            if (command == VSConstants.VSStd2KCmdID.TYPECHAR)
            {
                typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn);
                Log.DebugFormat("Typed Character: '{0}'", (typedChar == char.MinValue) ? "<null>" : typedChar.ToString());

                if (_activeSession == null &&
                    IsNotIntelliSenseTriggerWhenInStringLiteral(typedChar))
                {
                    isInStringArea = this.IsInStringArea(isInStringArea);
                    if (isInStringArea == true)
                    {
                        return(NextCommandHandler.Exec(ref pguidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut));
                    }
                }
            }
            else
            {
                Log.DebugFormat("Non-TypeChar command: '{0}'", ToCommandName(pguidCmdGroup, nCmdId));
            }

            switch (command)
            {
            case VSConstants.VSStd2KCmdID.RETURN:
                //check for a a selection
                if (_activeSession != null && !_activeSession.IsDismissed)
                {
                    //if the selection is fully selected, commit the current session
                    if (_activeSession.SelectedCompletionSet.SelectionStatus.IsSelected)
                    {
                        Log.Debug("Commit");
                        _activeSession.Commit();

                        //also, don't add the character to the buffer
                        return(VSConstants.S_OK);
                    }
                    else
                    {
                        Log.Debug("Dismiss");
                        //if there is no selection, dismiss the session
                        _activeSession.Dismiss();
                    }
                }
                break;

            case VSConstants.VSStd2KCmdID.TAB:
            case VSConstants.VSStd2KCmdID.BACKTAB:

                if (_activeSession != null && !_activeSession.IsDismissed)
                {
                    var completions = _activeSession.SelectedCompletionSet.Completions;
                    if (completions != null && completions.Count > 0)
                    {
                        var startPoint = _activeSession.SelectedCompletionSet.ApplicableTo.GetStartPoint(_textView.TextBuffer.CurrentSnapshot).Position;
                        _tabCompleteSession = new TabCompleteSession(_activeSession.SelectedCompletionSet.Completions, _activeSession.SelectedCompletionSet.SelectionStatus, startPoint);
                        _activeSession.Commit();

                        //also, don't add the character to the buffer
                        return(VSConstants.S_OK);
                    }
                    else
                    {
                        Log.Debug("Dismiss");
                        //If there are no completions, dismiss the session
                        _activeSession.Dismiss();
                    }
                }
                else if (_tabCompleteSession != null)
                {
                    if (command == VSConstants.VSStd2KCmdID.TAB)
                    {
                        _tabCompleteSession.ReplaceWithNextCompletion(_textView.TextBuffer, _textView.Caret.Position.BufferPosition.Position);
                    }
                    else
                    {
                        _tabCompleteSession.ReplaceWithPreviousCompletion(_textView.TextBuffer, _textView.Caret.Position.BufferPosition.Position);
                    }

                    //don't add the character to the buffer
                    return(VSConstants.S_OK);
                }
                else if (!Utilities.IsPrecedingTextInLineEmpty(_textView.Caret.Position.BufferPosition) && _textView.Selection.IsEmpty)
                {
                    _startTabComplete = true;
                    TriggerCompletion();

                    //don't add the character to the buffer
                    return(VSConstants.S_OK);
                }
                break;

            case VSConstants.VSStd2KCmdID.COMPLETEWORD:
                isInStringArea = this.IsInStringArea(isInStringArea);
                if (isInStringArea == true)
                {
                    return(NextCommandHandler.Exec(ref pguidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut));
                }

                TriggerCompletion();
                return(VSConstants.S_OK);

            default:
                break;
            }

            //check for a commit character
            if (char.IsWhiteSpace(typedChar) && _activeSession != null && !_activeSession.IsDismissed)
            {
                // If user is typing a variable, SPACE shouldn't commit the selection.
                // If the selection is fully matched with user's input, commit the current session and add the commit character to text buffer.
                if (_activeSession.SelectedCompletionSet.SelectionStatus.IsSelected &&
                    !_activeSession.SelectedCompletionSet.SelectionStatus.Completion.InsertionText.StartsWith("$", StringComparison.InvariantCulture))
                {
                    Log.Debug("Commit");
                    _activeSession.Commit();

                    bool isCompletionFullyMatched = false;
                    _textView.TextBuffer.Properties.TryGetProperty(BufferProperties.SessionCompletionFullyMatchedStatus, out isCompletionFullyMatched);
                    if (isCompletionFullyMatched)
                    {
                        // If user types all characters in a completion and click Space, then we should commit the selection and add the Space into text buffer.
                        return(NextCommandHandler.Exec(ref pguidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut));
                    }

                    //Don't add the character to the buffer if this commits the selection.
                    return(VSConstants.S_OK);
                }
                else
                {
                    Log.Debug("Dismiss");
                    //if there is no selection, dismiss the session
                    _activeSession.Dismiss();
                }
            }

            bool justCommitIntelliSense = false;

            if (IsIntelliSenseTriggerDot(typedChar) && _activeSession != null && !_activeSession.IsDismissed)
            {
                var selectionStatus = _activeSession.SelectedCompletionSet.SelectionStatus;
                if (selectionStatus.IsSelected)
                {
                    // If user types the full completion text, which ends with a dot, then we should just commit IntelliSense session ignore user's last typing.
                    ITrackingSpan lastWordSpan;
                    var           currentSnapshot = _textView.TextBuffer.CurrentSnapshot;
                    _textView.TextBuffer.Properties.TryGetProperty <ITrackingSpan>(BufferProperties.LastWordReplacementSpan, out lastWordSpan);
                    if (lastWordSpan != null)
                    {
                        string lastWordText        = lastWordSpan.GetText(currentSnapshot);
                        int    completionSpanStart = lastWordSpan.GetStartPoint(currentSnapshot);
                        int    completionSpanEnd   = _textView.Caret.Position.BufferPosition;
                        var    completionText      = currentSnapshot.GetText(completionSpanStart, completionSpanEnd - completionSpanStart);
                        completionText += typedChar;
                        Log.DebugFormat("completionSpanStart: {0}", completionSpanStart);
                        Log.DebugFormat("completionSpanEnd: {0}", completionSpanEnd);
                        Log.DebugFormat("completionText: {0}", completionText);

                        if (selectionStatus.Completion.InsertionText.Equals(completionText, StringComparison.OrdinalIgnoreCase))
                        {
                            Log.Debug(String.Format("Commited by {0}", typedChar));
                            _activeSession.Commit();
                            return(VSConstants.S_OK);
                        }
                    }

                    Log.Debug("Commit");
                    _activeSession.Commit();
                    justCommitIntelliSense = true;
                }
                else
                {
                    Log.Debug("Dismiss");
                    //if there is no selection, dismiss the session
                    _activeSession.Dismiss();
                }
            }

            // Check the char at caret before pass along the command
            // If command is backspace and completion session is active, then we need to see if the char to be deleted is an IntelliSense triggering char
            // If yes, then after deleting the char, we also dismiss the completion session
            // Otherwise, just filter the completion lists
            char charAtCaret = char.MinValue;

            if (command == VSConstants.VSStd2KCmdID.BACKSPACE && _activeSession != null && !_activeSession.IsDismissed)
            {
                int caretPosition = _textView.Caret.Position.BufferPosition.Position - 1;
                if (caretPosition >= 0)
                {
                    // caretPosition == -1 means caret is at the beginning of a file, which means no characters before it.
                    ITrackingPoint caretCharPosition = _textView.TextSnapshot.CreateTrackingPoint(caretPosition, PointTrackingMode.Positive);
                    charAtCaret = caretCharPosition.GetCharacter(_textView.TextSnapshot);
                }
            }

            // pass along the command so the char is added to the buffer
            int  retVal  = NextCommandHandler.Exec(ref pguidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut);
            bool handled = false;

            if (IsIntellisenseTrigger(typedChar) ||
                (justCommitIntelliSense || (IsIntelliSenseTriggerDot(typedChar) && IsPreviousTokenVariable())) || // If dot just commit a session or previous token before a dot was a variable, trigger intellisense
                (char.IsWhiteSpace(typedChar) && IsPreviousTokenParameter()))                                     // If the previous token before a space was a parameter, trigger intellisense
            {
                isInStringArea = this.IsInStringArea(isInStringArea);
                if (isInStringArea == false)
                {
                    TriggerCompletion();
                }
            }
            if (!typedChar.Equals(char.MinValue) && IsFilterTrigger(typedChar))
            {
                if (_activeSession != null)
                {
                    if (_activeSession.IsStarted)
                    {
                        try
                        {
                            Log.Debug("Filter");
                            _activeSession.Filter();
                        }
                        catch (Exception ex)
                        {
                            Log.Debug("Failed to filter session.", ex);
                        }
                    }
                }
            }
            else if (command == VSConstants.VSStd2KCmdID.BACKSPACE ||
                     command == VSConstants.VSStd2KCmdID.DELETE) //redo the filter if there is a deletion
            {
                if (_activeSession != null && !_activeSession.IsDismissed)
                {
                    try
                    {
                        if (_textView.Caret.Position.BufferPosition <= _completionCaretPosition)
                        {
                            Log.Debug("Dismiss");
                            _activeSession.Dismiss();
                        }
                        else
                        {
                            Log.Debug("Filter");
                            _activeSession.Filter();
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Debug("Failed to filter session.", ex);
                    }
                }

                handled = true;
            }
            if (handled)
            {
                return(VSConstants.S_OK);
            }
            return(retVal);
        }