private void EnsureTemplateResolutionResult() { if (_resolutionResultInitialized) { return; } _templateResolutionResult = TemplateListResolver.GetTemplateResolutionResult(_settingsLoader.UserTemplateCache.TemplateInfo, _hostDataLoader, _commandInput, _defaultLanguage); _singleMatchStatus = SingularInvokableMatchCheckStatus.None; // If any template in the group has any ambiguous params, it's not invokable. // The check for HasAmbiguousParameterValueMatch is for an example like: // "dotnet new mvc -f netcore" // - '-f netcore' is ambiguous in the 1.x version (2 begins-with matches) // - '-f netcore' is not ambiguous in the 2.x version (1 begins-with match) if (!_templateResolutionResult.TryGetUnambiguousTemplateGroupToUse(out IReadOnlyList <ITemplateMatchInfo> unambiguousTemplateGroup) || !_templateResolutionResult.TryGetSingularInvokableMatch(out _templateToInvoke, out _singleMatchStatus) || unambiguousTemplateGroup.Any(x => x.HasParameterMismatch()) || unambiguousTemplateGroup.Any(x => x.HasAmbiguousParameterValueMatch())) { _templateToInvoke = null; if (_singleMatchStatus == SingularInvokableMatchCheckStatus.AmbiguousChoice) { _environment.Host.LogDiagnosticMessage(LocalizableStrings.Authoring_AmbiguousChoiceParameterValue, "Authoring"); } else if (_singleMatchStatus == SingularInvokableMatchCheckStatus.AmbiguousPrecedence) { _environment.Host.LogDiagnosticMessage(LocalizableStrings.Authoring_AmbiguousBestPrecedence, "Authoring"); } } _resolutionResultInitialized = true; }
public bool TryGetSingularInvokableMatch(out ITemplateMatchInfo template, out SingularInvokableMatchCheckStatus resultStatus) { IReadOnlyList <ITemplateMatchInfo> invokableMatches = _coreMatchedTemplates.Where(x => x.IsInvokableMatch()).ToList(); IReadOnlyList <ITemplateMatchInfo> languageFilteredInvokableMatches; if (_hasUserInputLanguage) { languageFilteredInvokableMatches = invokableMatches; } else { // check for templates with the default language languageFilteredInvokableMatches = invokableMatches.Where(x => x.DispositionOfDefaults.Any(y => y.Location == MatchLocation.DefaultLanguage && y.Kind == MatchKind.Exact)).ToList(); // no candidate templates matched the default language, continue with the original candidates. if (languageFilteredInvokableMatches.Count == 0) { languageFilteredInvokableMatches = invokableMatches; } } if (languageFilteredInvokableMatches.Count == 1) { template = languageFilteredInvokableMatches[0]; resultStatus = SingularInvokableMatchCheckStatus.SingleMatch; return(true); } // if multiple templates in the group have single starts with matches on the same parameter, it's ambiguous. // For the case where one template has single starts with, and another has ambiguous - on the same param: // The one with single starts with is chosen as invokable because if the template with an ambiguous match // was not installed, the one with the singluar invokable would be chosen. HashSet <string> singleStartsWithParamNames = new HashSet <string>(); foreach (ITemplateMatchInfo checkTemplate in languageFilteredInvokableMatches) { IList <string> singleStartParamNames = checkTemplate.MatchDisposition.Where(x => x.Location == MatchLocation.OtherParameter && x.Kind == MatchKind.SingleStartsWith).Select(x => x.InputParameterName).ToList(); foreach (string paramName in singleStartParamNames) { if (!singleStartsWithParamNames.Add(paramName)) { template = null; resultStatus = SingularInvokableMatchCheckStatus.AmbiguousChoice; return(false); } } } ITemplateMatchInfo highestInGroupIfSingleGroup = TemplateListResolver.FindHighestPrecedenceTemplateIfAllSameGroupIdentity(languageFilteredInvokableMatches, out bool ambiguousGroupIdResult); if (highestInGroupIfSingleGroup != null) { template = highestInGroupIfSingleGroup; resultStatus = SingularInvokableMatchCheckStatus.SingleMatch; return(true); } else if (ambiguousGroupIdResult) { template = null; resultStatus = SingularInvokableMatchCheckStatus.AmbiguousPrecedence; return(false); } template = null; resultStatus = SingularInvokableMatchCheckStatus.NoMatch; return(false); }