MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Generic;6using System.Management.Automation.Internal;7 8namespace System.Management.Automation9{10 /// <summary>11 /// Implements the help provider for alias help.12 /// </summary>13 /// <remarks>14 /// Unlike other help providers, AliasHelpProvider directly inherits from HelpProvider15 /// instead of HelpProviderWithCache. This is because alias can be created/removed/updated16 /// in a Microsoft Command Shell session. And thus caching may result in old alias being cached.17 ///18 /// The real information for alias is stored in command help. To retrieve the real19 /// help information, help forwarding is needed.20 /// </remarks>21 internal class AliasHelpProvider : HelpProvider22 {23 /// <summary>24 /// Initializes a new instance of AliasHelpProvider class.25 /// </summary>26 internal AliasHelpProvider(HelpSystem helpSystem) : base(helpSystem)27 {28 _sessionState = helpSystem.ExecutionContext.SessionState;29 _commandDiscovery = helpSystem.ExecutionContext.CommandDiscovery;30 _context = helpSystem.ExecutionContext;31 }32 33 private readonly ExecutionContext _context;34 35 /// <summary>36 /// Session state for current Microsoft Command Shell session.37 /// </summary>38 /// <remarks>39 /// _sessionState is mainly used for alias help search in the case40 /// of wildcard search patterns. This is currently not achievable41 /// through _commandDiscovery.42 /// </remarks>43 private readonly SessionState _sessionState;44 45 /// <summary>46 /// Command Discovery object for current session.47 /// </summary>48 /// <remarks>49 /// _commandDiscovery is mainly used for exact match help for alias.50 /// The AliasInfo object returned from _commandDiscovery is essential51 /// in creating AliasHelpInfo.52 /// </remarks>53 private readonly CommandDiscovery _commandDiscovery;54 55 #region Common Properties56 57 /// <summary>58 /// Name of alias help provider.59 /// </summary>60 /// <value>Name of alias help provider</value>61 internal override string Name62 {63 get64 {65 return "Alias Help Provider";66 }67 }68 69 /// <summary>70 /// Help category of alias help provider, which is a constant: HelpCategory.Alias.71 /// </summary>72 /// <value>Help category of alias help provider.</value>73 internal override HelpCategory HelpCategory74 {75 get76 {77 return HelpCategory.Alias;78 }79 }80 81 #endregion82 83 #region Help Provider Interface84 85 /// <summary>86 /// Exact match an alias help target.87 /// </summary>88 /// <remarks>89 /// This will90 /// a. use _commandDiscovery object to retrieve AliasInfo object.91 /// b. Create AliasHelpInfo object based on AliasInfo object92 /// </remarks>93 /// <param name="helpRequest">Help request object.</param>94 /// <returns>Help info found.</returns>95 internal override IEnumerable<HelpInfo> ExactMatchHelp(HelpRequest helpRequest)96 {97 CommandInfo commandInfo = null;98 99 try100 {101 commandInfo = _commandDiscovery.LookupCommandInfo(helpRequest.Target);102 }103 catch (CommandNotFoundException)104 {105 // CommandNotFoundException is expected here if target doesn't match any106 // commandlet. Just ignore this exception and bail out.107 }108 109 if ((commandInfo != null) && (commandInfo.CommandType == CommandTypes.Alias))110 {111 AliasInfo aliasInfo = (AliasInfo)commandInfo;112 113 HelpInfo helpInfo = AliasHelpInfo.GetHelpInfo(aliasInfo);114 if (helpInfo != null)115 {116 yield return helpInfo;117 }118 }119 }120 121 /// <summary>122 /// Search an alias help target.123 /// </summary>124 /// <remarks>125 /// This will,126 /// a. use _sessionState object to get a list of alias that match the target.127 /// b. for each alias, retrieve help info as in ExactMatchHelp.128 /// </remarks>129 /// <param name="helpRequest">Help request object.</param>130 /// <param name="searchOnlyContent">131 /// If true, searches for pattern in the help content. Individual132 /// provider can decide which content to search in.133 ///134 /// If false, searches for pattern in the command names.135 /// </param>136 /// <returns>A IEnumerable of helpinfo object.</returns>137 internal override IEnumerable<HelpInfo> SearchHelp(HelpRequest helpRequest, bool searchOnlyContent)138 {139 // aliases do not have help content...so doing nothing in that case140 if (!searchOnlyContent)141 {142 string target = helpRequest.Target;143 string pattern = target;144 var allAliases = new HashSet<string>(StringComparer.OrdinalIgnoreCase);145 146 if (!WildcardPattern.ContainsWildcardCharacters(target))147 {148 pattern += "*";149 }150 151 WildcardPattern matcher = WildcardPattern.Get(pattern, WildcardOptions.IgnoreCase);152 IDictionary<string, AliasInfo> aliasTable = _sessionState.Internal.GetAliasTable();153 154 foreach (string name in aliasTable.Keys)155 {156 if (matcher.IsMatch(name))157 {158 HelpRequest exactMatchHelpRequest = helpRequest.Clone();159 exactMatchHelpRequest.Target = name;160 // Duplicates??161 foreach (HelpInfo helpInfo in ExactMatchHelp(exactMatchHelpRequest))162 {163 // Component/Role/Functionality match is done only for SearchHelp164 // as "get-help * -category alias" should not forward help to165 // CommandHelpProvider..(ExactMatchHelp does forward help to166 // CommandHelpProvider)167 if (!Match(helpInfo, helpRequest))168 {169 continue;170 }171 172 if (allAliases.Contains(name))173 {174 continue;175 }176 177 allAliases.Add(name);178 179 yield return helpInfo;180 }181 }182 }183 184 CommandSearcher searcher =185 new CommandSearcher(186 pattern,187 SearchResolutionOptions.ResolveAliasPatterns, CommandTypes.Alias,188 _context);189 190 while (searcher.MoveNext())191 {192 CommandInfo current = ((IEnumerator<CommandInfo>)searcher).Current;193 194 if (_context.CurrentPipelineStopping)195 {196 yield break;197 }198 199 AliasInfo alias = current as AliasInfo;200 201 if (alias != null)202 {203 string name = alias.Name;204 HelpRequest exactMatchHelpRequest = helpRequest.Clone();205 exactMatchHelpRequest.Target = name;206 207 // Duplicates??208 foreach (HelpInfo helpInfo in ExactMatchHelp(exactMatchHelpRequest))209 {210 // Component/Role/Functionality match is done only for SearchHelp211 // as "get-help * -category alias" should not forward help to212 // CommandHelpProvider..(ExactMatchHelp does forward help to213 // CommandHelpProvider)214 if (!Match(helpInfo, helpRequest))215 {216 continue;217 }218 219 if (allAliases.Contains(name))220 {221 continue;222 }223 224 allAliases.Add(name);225 226 yield return helpInfo;227 }228 }229 }230 231 foreach (CommandInfo current in ModuleUtils.GetMatchingCommands(pattern, _context, helpRequest.CommandOrigin))232 {233 if (_context.CurrentPipelineStopping)234 {235 yield break;236 }237 238 AliasInfo alias = current as AliasInfo;239 240 if (alias != null)241 {242 string name = alias.Name;243 244 HelpInfo helpInfo = AliasHelpInfo.GetHelpInfo(alias);245 246 if (allAliases.Contains(name))247 {248 continue;249 }250 251 allAliases.Add(name);252 253 yield return helpInfo;254 }255 }256 }257 }258 259 private static bool Match(HelpInfo helpInfo, HelpRequest helpRequest)260 {261 if (helpRequest == null)262 return true;263 264 if ((helpRequest.HelpCategory & helpInfo.HelpCategory) == 0)265 {266 return false;267 }268 269 if (!Match(helpInfo.Component, helpRequest.Component))270 {271 return false;272 }273 274 if (!Match(helpInfo.Role, helpRequest.Role))275 {276 return false;277 }278 279 if (!Match(helpInfo.Functionality, helpRequest.Functionality))280 {281 return false;282 }283 284 return true;285 }286 287 private static bool Match(string target, string[] patterns)288 {289 // patterns should never be null as shell never accepts290 // empty inputs. Keeping this check as a safe measure.291 if (patterns == null || patterns.Length == 0)292 return true;293 294 foreach (string pattern in patterns)295 {296 if (Match(target, pattern))297 {298 // we have a match so return true299 return true;300 }301 }302 303 // We dont have a match so far..so return false304 return false;305 }306 307 private static bool Match(string target, string pattern)308 {309 if (string.IsNullOrEmpty(pattern))310 return true;311 312 if (string.IsNullOrEmpty(target))313 target = string.Empty;314 315 WildcardPattern matcher = WildcardPattern.Get(pattern, WildcardOptions.IgnoreCase);316 317 return matcher.IsMatch(target);318 }319 320 #endregion321 }322}323 