public void ExecuteCommand(TypeCharCommandArgs args, Action nextHandler, CommandExecutionContext context)
        {
            var originalCaretPosition = args.TextView.GetCaretPoint(args.SubjectBuffer) ?? -1;

            // Ensure the character is actually typed in the editor
            nextHandler();

            if (args.TypedChar != TriggerCharacter)
            {
                return;
            }

            CompleteComment(args.SubjectBuffer, args.TextView, originalCaretPosition, InsertOnCharacterTyped, CancellationToken.None);
        }
コード例 #2
0
        public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext)
        {
            AssertIsForeground();
            if (args.TypedChar == ';' &&
                AreSnippetsEnabled(args) &&
                args.TextView.Properties.TryGetProperty(typeof(AbstractSnippetExpansionClient), out AbstractSnippetExpansionClient snippetExpansionClient) &&
                snippetExpansionClient.IsFullMethodCallSnippet)
            {
                // Commit the snippet. Leave the caret in place, but clear the selection. Subsequent handlers in the
                // chain will handle the remaining Complete Statement (';' insertion) operations only if there is no
                // active selection.
                snippetExpansionClient.CommitSnippet(leaveCaret: true);
                args.TextView.Selection.Clear();
            }

            nextCommandHandler();
        }
コード例 #3
0
        public void Verify(string initialMarkup, string expectedMarkup, char typeChar)
        {
            using (var workspace = CreateTestWorkspace(initialMarkup))
            {
                var testDocument = workspace.Documents.Single();
                var view         = testDocument.GetTextView();
                view.Caret.MoveTo(
                    new SnapshotPoint(view.TextSnapshot, testDocument.CursorPosition.Value)
                    );

                var commandHandler = CreateCommandHandler(workspace);

                var args        = new TypeCharCommandArgs(view, view.TextBuffer, typeChar);
                var nextHandler = CreateInsertTextHandler(view, typeChar.ToString());

                commandHandler.ExecuteCommand(
                    args,
                    nextHandler,
                    TestCommandExecutionContext.Create()
                    );
                MarkupTestFile.GetPosition(
                    expectedMarkup,
                    out var expectedCode,
                    out int expectedPosition
                    );

                Assert.Equal(expectedCode, view.TextSnapshot.GetText());

                var caretPosition = view.Caret.Position.BufferPosition.Position;
                Assert.True(
                    expectedPosition == caretPosition,
                    string.Format(
                        "Caret positioned incorrectly. Should have been {0}, but was {1}.",
                        expectedPosition,
                        caretPosition
                        )
                    );
            }
        }
コード例 #4
0
        protected void VerifyTypingCharacter(
            string initialMarkup,
            string expectedMarkup,
            bool useTabs = false,
            bool autoGenerateXmlDocComments = true,
            string newLine = "\r\n"
            )
        {
            Verify(
                initialMarkup,
                expectedMarkup,
                useTabs,
                autoGenerateXmlDocComments,
                newLine: newLine,
                execute: (workspace, view, editorOperationsFactoryService) =>
            {
                var commandHandler = CreateCommandHandler(workspace);

                var commandArgs = new TypeCharCommandArgs(
                    view,
                    view.TextBuffer,
                    DocumentationCommentCharacter
                    );
                var nextHandler = CreateInsertTextHandler(
                    view,
                    DocumentationCommentCharacter.ToString()
                    );

                commandHandler.ExecuteCommand(
                    commandArgs,
                    nextHandler,
                    TestCommandExecutionContext.Create()
                    );
            }
                );
        }
コード例 #5
0
        void IChainedCommandHandler <TypeCharCommandArgs> .ExecuteCommand(TypeCharCommandArgs args, Action nextHandler, CommandExecutionContext context)
        {
            AssertIsForeground();

            var allProviders = GetProviders();

            if (allProviders == null)
            {
                nextHandler();
                return;
            }

            // Note: while we're doing this, we don't want to hear about buffer changes (since we
            // know they're going to happen).  So we disconnect and reconnect to the event
            // afterwards.  That way we can hear about changes to the buffer that don't happen
            // through us.
            this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged;
            try
            {
                nextHandler();
            }
            finally
            {
                this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged;
            }

            // We only want to process typechar if it is a normal typechar and no one else is
            // involved.  i.e. if there was a typechar, but someone processed it and moved the caret
            // somewhere else then we don't want signature help.  Also, if a character was typed but
            // something intercepted and placed different text into the editor, then we don't want
            // to proceed.
            //
            // Note: we do not want to pass along a text version here.  It is expected that multiple
            // version changes may happen when we call 'nextHandler' and we will still want to
            // proceed.  For example, if the user types "WriteL(", then that will involve two text
            // changes as completion commits that out to "WriteLine(".  But we still want to provide
            // sig help in this case.
            if (this.TextView.TypeCharWasHandledStrangely(this.SubjectBuffer, args.TypedChar))
            {
                // If we were computing anything, we stop.  We only want to process a typechar
                // if it was a normal character.
                DismissSessionIfActive();
                return;
            }

            // Separate the sig help providers into two buckets; one bucket for those that were triggered
            // by the typed character, and those that weren't.  To keep our queries to a minimum, we first
            // check with the textually triggered providers.  If none of those produced any sig help items
            // then we query the other providers to see if they can produce anything viable.  This takes
            // care of cases where the filtered set of providers didn't provide anything but one of the
            // other providers could still be valid, but doesn't explicitly treat the typed character as
            // a trigger character.
            var(textuallyTriggeredProviders, untriggeredProviders) = FilterProviders(allProviders, args.TypedChar);
            var triggerInfo = new SignatureHelpTriggerInfo(SignatureHelpTriggerReason.TypeCharCommand, args.TypedChar);

            if (!IsSessionActive)
            {
                // No computation at all.  If this is not a trigger character, we just ignore it and
                // stay in this state.  Otherwise, if it's a trigger character, start up a new
                // computation and start computing the model in the background.
                if (textuallyTriggeredProviders.Any())
                {
                    // First create the session that represents that we now have a potential
                    // signature help list. Then tell it to start computing.
                    StartSession(textuallyTriggeredProviders, triggerInfo);
                    return;
                }
                else
                {
                    // No need to do anything.  Just stay in the state where we have no session.
                    return;
                }
            }
            else
            {
                var computed = false;
                if (allProviders.Any(p => p.IsRetriggerCharacter(args.TypedChar)))
                {
                    // The user typed a character that might close the scope of the current model.
                    // In this case, we should requery all providers.
                    //
                    // e.g.     Math.Max(Math.Min(1,2)$$
                    sessionOpt.ComputeModel(allProviders, new SignatureHelpTriggerInfo(SignatureHelpTriggerReason.RetriggerCommand, triggerInfo.TriggerCharacter));
                    computed = true;
                }

                if (textuallyTriggeredProviders.Any())
                {
                    // The character typed was something like "(".  It can both filter a list if
                    // it was in a string like: Foo(bar, "(
                    //
                    // Or it can trigger a new list. Ask the computation to compute again.
                    sessionOpt.ComputeModel(
                        textuallyTriggeredProviders.Concat(untriggeredProviders), triggerInfo);
                    computed = true;
                }

                if (!computed)
                {
                    // A character was typed and we haven't updated our model; do so now.
                    sessionOpt.ComputeModel(allProviders, new SignatureHelpTriggerInfo(SignatureHelpTriggerReason.RetriggerCommand));
                }
            }
        }
コード例 #6
0
        void ICommandHandler <TypeCharCommandArgs> .ExecuteCommand(TypeCharCommandArgs args, Action nextHandler)
        {
            Trace.WriteLine("Entered completion command handler for typechar.");

            AssertIsForeground();

            var initialCaretPosition = GetCaretPointInViewBuffer();

            // When a character is typed it is *always* sent through to the editor.  This way the
            // editor always represents what would have been typed had completion not been involved
            // at this point.  After we send the character into the buffer we then decide what to do
            // with the completion set.  If we decide to commit it then we will replace the
            // appropriate span (which will include the character just sent to the buffer) with the
            // appropriate insertion text *and* the character typed.  This way, after we commit, the
            // editor has the insertion text of the selected item, and the character typed.  It
            // also means that if we then undo that we'll see the text that would have been typed
            // had no completion been active.

            // Note: while we're doing this, we don't want to hear about buffer changes (since we
            // know they're going to happen).  So we disconnect and reconnect to the event
            // afterwards.  That way we can hear about changes to the buffer that don't happen
            // through us.

            // Automatic Brace Completion may also move the caret, so unsubscribe from that too
            this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged;
            this.TextView.Caret.PositionChanged  -= OnCaretPositionChanged;

            // In Venus/Razor, the user might be typing on the buffer's seam. This means that,
            // depending on the character typed, the character may not go into our buffer.
            var isOnSeam = IsOnSeam();

            try
            {
                nextHandler();
            }
            finally
            {
                this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged;
                this.TextView.Caret.PositionChanged  += OnCaretPositionChanged;
            }

            // We only want to process typechar if it is a normal typechar and no one else is
            // involved.  i.e. if there was a typechar, but someone processed it and moved the caret
            // somewhere else then we don't want completion.  Also, if a character was typed but
            // something intercepted and placed different text into the editor, then we don't want
            // to proceed.
            if (this.TextView.TypeCharWasHandledStrangely(this.SubjectBuffer, args.TypedChar))
            {
                Trace.WriteLine("typechar was handled by someone else, cannot have a completion session.");

                if (sessionOpt != null)
                {
                    // If we're on a seam (razor) with a computation, and the user types a character
                    // that goes into the other side of the seam, the character may be a commit character.
                    // If it's a commit character, just commit without trying to check caret position,
                    // since the caret is no longer in our buffer.
                    if (isOnSeam && this.IsCommitCharacter(args.TypedChar))
                    {
                        Trace.WriteLine("typechar was on seam and a commit char, cannot have a completion session.");

                        this.CommitOnTypeChar(args.TypedChar);
                        return;
                    }
                    else if (_autoBraceCompletionChars.Contains(args.TypedChar) &&
                             this.SubjectBuffer.GetOption(InternalFeatureOnOffOptions.AutomaticPairCompletion) &&
                             this.IsCommitCharacter(args.TypedChar))
                    {
                        Trace.WriteLine("typechar was brace completion char and a commit char, cannot have a completion session.");

                        // I don't think there is any better way than this. if typed char is one of auto brace completion char,
                        // we don't do multiple buffer change check
                        this.CommitOnTypeChar(args.TypedChar);
                        return;
                    }
                    else
                    {
                        Trace.WriteLine("we stop model computation, cannot have a completion session.");

                        // If we were computing anything, we stop.  We only want to process a typechar
                        // if it was a normal character.
                        this.StopModelComputation();
                    }
                }

                return;
            }

            var completionService = this.GetCompletionService();

            if (completionService == null)
            {
                Trace.WriteLine("handling typechar, completion service is null, cannot have a completion session.");

                return;
            }

            var options = GetOptions();

            Contract.ThrowIfNull(options);

            var isTextuallyTriggered       = IsTextualTriggerCharacter(completionService, args.TypedChar, options);
            var isPotentialFilterCharacter = IsPotentialFilterCharacter(args);
            var trigger = CompletionTrigger.CreateInsertionTrigger(args.TypedChar);

            if (sessionOpt == null)
            {
                // No computation at all.  If this is not a trigger character, we just ignore it and
                // stay in this state.  Otherwise, if it's a trigger character, start up a new
                // computation and start computing the model in the background.
                if (isTextuallyTriggered)
                {
                    Trace.WriteLine("no completion session yet and this is a trigger char, starting model computation.");

                    // First create the session that represents that we now have a potential
                    // completion list.  Then tell it to start computing.
                    StartNewModelComputation(completionService, trigger, filterItems: true);
                    return;
                }
                else
                {
                    Trace.WriteLine("no completion session yet and this is NOT a trigger char, we won't have completion.");

                    // No need to do anything.  Just stay in the state where we have no session.
                    return;
                }
            }
            else
            {
                Trace.WriteLine("we have a completion session.");

                sessionOpt.UpdateModelTrackingSpan(initialCaretPosition);

                // If the session is up, it may be in one of many states.  It may know nothing
                // (because it is currently computing the list of completions).  Or it may have a
                // list of completions that it has filtered.

                // If the user types something which is absolutely known to be a filter character
                // then we can just proceed without blocking.
                if (isPotentialFilterCharacter)
                {
                    if (isTextuallyTriggered)
                    {
                        Trace.WriteLine("computing completion again and filtering...");

                        // The character typed was something like "a".  It can both filter a list if
                        // we have computed one, or it can trigger a new list.  Ask the computation
                        // to compute again. If nothing has been computed, then it will try to
                        // compute again, otherwise it will just ignore this request.
                        sessionOpt.ComputeModel(completionService, trigger, _roles, options);
                    }

                    // Now filter whatever result we have.
                    sessionOpt.FilterModel(CompletionFilterReason.TypeChar);
                }
                else
                {
                    // It wasn't a trigger or filter character. At this point, we make our
                    // determination on what to do based on what has actually been computed and
                    // what's being typed. This means waiting on the session and will effectively
                    // block the user.

                    // Again, from this point on we must block on the computation to decide what to
                    // do.

                    // What they type may end up filtering, committing, or else will dismiss.
                    //
                    // For example, we may filter in cases like this: "Color."
                    //
                    // "Color" will have already filtered the list down to some things like
                    // "Color", "Color.Red", "Color.Blue", etc.  When we process the 'dot', we
                    // actually want to filter some more.  But we can't know that ahead of time until
                    // we have computed the list of completions.
                    if (this.IsFilterCharacter(args.TypedChar))
                    {
                        Trace.WriteLine("filtering the session...");

                        // Known to be a filter character for the currently selected item.  So just
                        // filter the session.
                        sessionOpt.FilterModel(CompletionFilterReason.TypeChar);
                        return;
                    }

                    // It wasn't a filter character.  We'll either commit what's selected, or we'll
                    // dismiss the completion list.  First, ensure that what was typed is in the
                    // buffer.

                    // Now, commit if it was a commit character.
                    if (this.IsCommitCharacter(args.TypedChar))
                    {
                        Trace.WriteLine("committing the session...");

                        // Known to be a commit character for the currently selected item.  So just
                        // commit the session.
                        this.CommitOnTypeChar(args.TypedChar);
                    }
                    else
                    {
                        Trace.WriteLine("dismissing the session...");

                        // Now dismiss the session.
                        this.StopModelComputation();
                    }

                    // The character may commit/dismiss and then trigger completion again. So check
                    // for that here.

                    if (isTextuallyTriggered)
                    {
                        Trace.WriteLine("the char commit/dismiss -ed a session and is trigerring completion again. starting model computation.");

                        // First create the session that represents that we now have a potential
                        // completion list.
                        StartNewModelComputation(completionService, trigger, filterItems: true);
                        return;
                    }
                }
            }
        }
コード例 #7
0
 private void ExecuteCommand(TypeCharCommandArgs args, Action nextHandler, CancellationToken cancellationToken)
 {
     ExecuteReturnOrTypeCommand(args, nextHandler, cancellationToken);
 }
コード例 #8
0
 public void ExecuteCommand(TypeCharCommandArgs args, Action nextHandler, CommandExecutionContext context)
 {
     ExecuteCommand(args, nextHandler, CancellationToken.None);
 }
コード例 #9
0
 public VSCommanding.CommandState GetCommandState(TypeCharCommandArgs args, Func <VSCommanding.CommandState> nextHandler)
 {
     return(nextHandler());
 }
コード例 #10
0
 public bool ExecuteCommand(TypeCharCommandArgs args, CommandExecutionContext executionContext)
 {
     return(false);
 }
コード例 #11
0
 void ICommandHandler <TypeCharCommandArgs> .ExecuteCommand(TypeCharCommandArgs args, System.Action nextHandler)
 {
     AssertIsForeground();
     ExecuteCommandWorker(args, nextHandler);
 }
コード例 #12
0
 CommandState ICommandHandler <TypeCharCommandArgs> .GetCommandState(TypeCharCommandArgs args, System.Func <CommandState> nextHandler)
 {
     AssertIsForeground();
     return(GetCommandStateWorker(args, nextHandler));
 }
コード例 #13
0
        VSCommanding.CommandState IChainedCommandHandler <TypeCharCommandArgs> .GetCommandState(TypeCharCommandArgs args, Func <VSCommanding.CommandState> nextHandler)
        {
            AssertIsForeground();

            // We just defer to the editor here.  We do not interfere with typing normal characters.
            return(nextHandler());
        }
コード例 #14
0
 void IChainedCommandHandler <TypeCharCommandArgs> .ExecuteCommand(TypeCharCommandArgs args, Action nextHandler, CommandExecutionContext context)
 {
     AssertIsForeground();
     ExecuteCommandWorker(args, nextHandler, context);
 }
コード例 #15
0
 CommandState ICommandHandler <TypeCharCommandArgs> .GetCommandState(TypeCharCommandArgs args)
 {
     return(args.TypedChar == '\0' ? CommandState.Unavailable : AvailableInEditableView(args.TextView));
 }
コード例 #16
0
 public CommandState GetCommandState(TypeCharCommandArgs args, Func <CommandState> nextHandler)
 => nextHandler();
コード例 #17
0
        void ICommandHandler <TypeCharCommandArgs> .ExecuteCommand(TypeCharCommandArgs args, Action nextHandler)
        {
            AssertIsForeground();

            // When a character is typed it is *always* sent through to the editor.  This way the
            // editor always represents what would have been typed had completion not been involved
            // at this point.  That means that if we decide to commit, then undo'ing the commit will
            // return you to the code that you would have typed if completion was not up.
            //
            // The steps we follow for commit are as follows:
            //
            //      1) send the commit character through to the buffer.
            //      2) open a transaction.
            //          2a) roll back the text to before the text was sent through
            //          2b) commit the item.
            //          2c) send the commit character through again.*
            //          2d) commit the transaction.
            //
            // 2c is very important.  it makes sure that post our commit all our normal features
            // run depending on what got typed.  For example if the commit character was (
            // then brace completion may run.  If it was ; then formatting may run.  But, importantly
            // this code doesn't need to know anything about that.  Furthermore, because that code
            // runs within this transaction, then the user can always undo and get to what the code
            // would have been if completion was not involved.
            //
            // 2c*: note sending the commit character through to the buffer again can be controlled
            // by the completion item.  For example, completion items that want to totally handle
            // what gets output into the buffer can ask for this not to happen.  An example of this
            // is override completion.  If the user types "override Method(" then we'll want to
            // spit out the entire method and *not* also spit out "(" again.

            // In order to support 2a (rolling back), we capture hte state of the buffer before
            // we send the character through.  We then just apply the edits in reverse order to
            // roll us back.
            var initialTextSnapshot = this.SubjectBuffer.CurrentSnapshot;

            var initialCaretPosition = GetCaretPointInViewBuffer();

            // Note: while we're doing this, we don't want to hear about buffer changes (since we
            // know they're going to happen).  So we disconnect and reconnect to the event
            // afterwards.  That way we can hear about changes to the buffer that don't happen
            // through us.

            // Automatic Brace Completion may also move the caret, so unsubscribe from that too
            this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged;
            this.TextView.Caret.PositionChanged  -= OnCaretPositionChanged;

            // In Venus/Razor, the user might be typing on the buffer's seam. This means that,
            // depending on the character typed, the character may not go into our buffer.
            var isOnSeam = IsOnSeam();

            try
            {
                nextHandler();
            }
            finally
            {
                this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged;
                this.TextView.Caret.PositionChanged  += OnCaretPositionChanged;
            }

            // We only want to process typechar if it is a normal typechar and no one else is
            // involved.  i.e. if there was a typechar, but someone processed it and moved the caret
            // somewhere else then we don't want completion.  Also, if a character was typed but
            // something intercepted and placed different text into the editor, then we don't want
            // to proceed.
            if (this.TextView.TypeCharWasHandledStrangely(this.SubjectBuffer, args.TypedChar))
            {
                if (sessionOpt != null)
                {
                    // If we're on a seam (razor) with a computation, and the user types a character
                    // that goes into the other side of the seam, the character may be a commit character.
                    // If it's a commit character, just commit without trying to check caret position,
                    // since the caret is no longer in our buffer.
                    if (isOnSeam && this.IsCommitCharacter(args.TypedChar))
                    {
                        this.CommitOnTypeChar(args.TypedChar, initialTextSnapshot, nextHandler);
                        return;
                    }
                    else if (_autoBraceCompletionChars.Contains(args.TypedChar) &&
                             this.SubjectBuffer.GetOption(InternalFeatureOnOffOptions.AutomaticPairCompletion) &&
                             this.IsCommitCharacter(args.TypedChar))
                    {
                        // I don't think there is any better way than this. if typed char is one of auto brace completion char,
                        // we don't do multiple buffer change check
                        this.CommitOnTypeChar(args.TypedChar, initialTextSnapshot, nextHandler);
                        return;
                    }
                    else
                    {
                        // If we were computing anything, we stop.  We only want to process a typechar
                        // if it was a normal character.
                        this.StopModelComputation();
                    }
                }

                return;
            }

            var completionService = this.GetCompletionService();

            if (completionService == null)
            {
                return;
            }

            var options = GetOptions();

            Contract.ThrowIfNull(options);

            var isTextuallyTriggered       = IsTextualTriggerCharacter(completionService, args.TypedChar, options);
            var isPotentialFilterCharacter = IsPotentialFilterCharacter(args);
            var trigger = CompletionTrigger.CreateInsertionTrigger(args.TypedChar);

            if (sessionOpt == null)
            {
                // No computation at all.  If this is not a trigger character, we just ignore it and
                // stay in this state.  Otherwise, if it's a trigger character, start up a new
                // computation and start computing the model in the background.
                if (isTextuallyTriggered)
                {
                    // First create the session that represents that we now have a potential
                    // completion list.  Then tell it to start computing.
                    StartNewModelComputation(completionService, trigger, filterItems: true, dismissIfEmptyAllowed: true);
                    return;
                }
                else
                {
                    // No need to do anything.  Just stay in the state where we have no session.
                    return;
                }
            }
            else
            {
                sessionOpt.UpdateModelTrackingSpan(initialCaretPosition);

                // If the session is up, it may be in one of many states.  It may know nothing
                // (because it is currently computing the list of completions).  Or it may have a
                // list of completions that it has filtered.

                // If the user types something which is absolutely known to be a filter character
                // then we can just proceed without blocking.
                if (isPotentialFilterCharacter)
                {
                    if (isTextuallyTriggered)
                    {
                        // The character typed was something like "a".  It can both filter a list if
                        // we have computed one, or it can trigger a new list.  Ask the computation
                        // to compute again. If nothing has been computed, then it will try to
                        // compute again, otherwise it will just ignore this request.
                        sessionOpt.ComputeModel(completionService, trigger, _roles, options);
                    }

                    // Now filter whatever result we have.
                    sessionOpt.FilterModel(
                        CompletionFilterReason.TypeChar,
                        recheckCaretPosition: false,
                        dismissIfEmptyAllowed: true,
                        filterState: null);
                }
                else
                {
                    // It wasn't a trigger or filter character. At this point, we make our
                    // determination on what to do based on what has actually been computed and
                    // what's being typed. This means waiting on the session and will effectively
                    // block the user.

                    // Again, from this point on we must block on the computation to decide what to
                    // do.

                    // What they type may end up filtering, committing, or else will dismiss.
                    //
                    // For example, we may filter in cases like this: "Color."
                    //
                    // "Color" will have already filtered the list down to some things like
                    // "Color", "Color.Red", "Color.Blue", etc.  When we process the 'dot', we
                    // actually want to filter some more.  But we can't know that ahead of time until
                    // we have computed the list of completions.
                    if (this.IsFilterCharacter(args.TypedChar))
                    {
                        // Known to be a filter character for the currently selected item.  So just
                        // filter the session.
                        sessionOpt.FilterModel(CompletionFilterReason.TypeChar,
                                               recheckCaretPosition: false,
                                               dismissIfEmptyAllowed: true,
                                               filterState: null);
                        return;
                    }

                    // It wasn't a filter character.  We'll either commit what's selected, or we'll
                    // dismiss the completion list.  First, ensure that what was typed is in the
                    // buffer.

                    // Now, commit if it was a commit character.
                    if (this.IsCommitCharacter(args.TypedChar))
                    {
                        // Known to be a commit character for the currently selected item.  So just
                        // commit the session.
                        this.CommitOnTypeChar(args.TypedChar, initialTextSnapshot, nextHandler);
                    }
                    else
                    {
                        // Now dismiss the session.
                        this.StopModelComputation();
                    }

                    // The character may commit/dismiss and then trigger completion again. So check
                    // for that here.

                    if (isTextuallyTriggered)
                    {
                        // First create the session that represents that we now have a potential
                        // completion list.
                        StartNewModelComputation(
                            completionService, trigger, filterItems: true, dismissIfEmptyAllowed: true);
                        return;
                    }
                }
            }
        }
コード例 #18
0
 public void ExecuteCommand(TypeCharCommandArgs args, Action nextHandler, CommandExecutionContext context)
 {
     ExecuteReturnOrTypeCommand(args, nextHandler, context.OperationContext.UserCancellationToken);
 }
コード例 #19
0
 public CommandState GetCommandState(TypeCharCommandArgs args, Func <CommandState> nextCommandHandler)
 {
     return(nextCommandHandler());
 }
コード例 #20
0
 public CommandState GetCommandState(TypeCharCommandArgs args) => CommandState.Unspecified;