public async Task <SignatureHelpItems?> GetItemsAsync(Document document, int position, SignatureHelpTriggerInfo trigger, CancellationToken cancellationToken) { Microsoft.CodeAnalysis.SignatureHelp.SignatureHelpItems?bestItems = null; // TODO(cyrusn): We're calling into extensions, we need to make ourselves resilient // to the extension crashing. foreach (var provider in _providers) { cancellationToken.ThrowIfCancellationRequested(); var currentItems = await provider.GetItemsAsync(document, position, trigger.Inner, cancellationToken).ConfigureAwait(false); if (currentItems != null && currentItems.ApplicableSpan.IntersectsWith(position)) { // If another provider provides sig help items, then only take them if they // start after the last batch of items. i.e. we want the set of items that // conceptually are closer to where the caret position is. This way if you have: // // Foo(new Bar($$ // // Then invoking sig help will only show the items for "new Bar(" and not also // the items for "Foo(..." if (IsBetter(bestItems, currentItems.ApplicableSpan)) { bestItems = currentItems; } } } if (bestItems != null) { var items = new SignatureHelpItems(bestItems); if (items.SelectedItemIndex == null) { var selection = DefaultSignatureHelpSelector.GetSelection(items.Items, null, false, items.ArgumentIndex, items.ArgumentCount, items.ArgumentName, isCaseSensitive: true); if (selection.SelectedItem != null) { items.SelectedItemIndex = items.Items.IndexOf(selection.SelectedItem); } } return(items); } return(null); }
SignatureHelpResult GetSignatureHelpResult(Tuple <ISignatureHelpProvider, SignatureHelpItems> res, Document document) { // Code is from the end of ComputeModelInBackgroundAsync() var items = res.Item2; if (items == null) { return(null); } var selectedItem = GetSelectedItem(items, res.Item1); var syntaxFactsService = document?.Project?.LanguageServices?.GetService <Microsoft.CodeAnalysis.LanguageServices.ISyntaxFactsService>(); var isCaseSensitive = syntaxFactsService == null || syntaxFactsService.IsCaseSensitive; var selection = DefaultSignatureHelpSelector.GetSelection(items.Items, selectedItem, items.ArgumentIndex, items.ArgumentCount, items.ArgumentName, isCaseSensitive); return(new SignatureHelpResult(items, selection.SelectedItem, selection.SelectedParameter)); }
private async Task <Model> ComputeModelInBackgroundAsync( Model currentModel, ImmutableArray <ISignatureHelpProvider> providers, SnapshotPoint caretPosition, DisconnectedBufferGraph disconnectedBufferGraph, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { try { using (Logger.LogBlock(FunctionId.SignatureHelp_ModelComputation_ComputeModelInBackground, cancellationToken)) { AssertIsBackground(); cancellationToken.ThrowIfCancellationRequested(); var document = Controller.DocumentProvider.GetDocument(caretPosition.Snapshot, cancellationToken); if (document == null) { return(currentModel); } if (triggerInfo.TriggerReason == SignatureHelpTriggerReason.RetriggerCommand) { if (currentModel == null) { return(null); } if (triggerInfo.TriggerCharacter.HasValue && !currentModel.Provider.IsRetriggerCharacter(triggerInfo.TriggerCharacter.Value)) { return(currentModel); } } // first try to query the providers that can trigger on the specified character var(provider, items) = await ComputeItemsAsync( providers, caretPosition, triggerInfo, document, cancellationToken).ConfigureAwait(false); if (provider == null) { // No provider produced items. So we can't produce a model return(null); } if (currentModel != null && currentModel.Provider == provider && currentModel.GetCurrentSpanInSubjectBuffer(disconnectedBufferGraph.SubjectBufferSnapshot).Span.Start == items.ApplicableSpan.Start && currentModel.Items.IndexOf(currentModel.SelectedItem) == items.SelectedItemIndex && currentModel.ArgumentIndex == items.ArgumentIndex && currentModel.ArgumentCount == items.ArgumentCount && currentModel.ArgumentName == items.ArgumentName) { // The new model is the same as the current model. Return the currentModel // so we keep the active selection. return(currentModel); } var selectedItem = GetSelectedItem(currentModel, items, provider, out var userSelected); var model = new Model(disconnectedBufferGraph, items.ApplicableSpan, provider, items.Items, selectedItem, items.ArgumentIndex, items.ArgumentCount, items.ArgumentName, selectedParameter: 0, userSelected); var syntaxFactsService = document.GetLanguageService <ISyntaxFactsService>(); var isCaseSensitive = syntaxFactsService == null || syntaxFactsService.IsCaseSensitive; var selection = DefaultSignatureHelpSelector.GetSelection(model.Items, model.SelectedItem, model.UserSelected, model.ArgumentIndex, model.ArgumentCount, model.ArgumentName, isCaseSensitive); return(model.WithSelectedItem(selection.SelectedItem, selection.UserSelected) .WithSelectedParameter(selection.SelectedParameter)); } } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }