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);
        }