@@ -17,8 +17,8 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility
17
17
/// </summary>
18
18
internal static class CommandHelpers
19
19
{
20
- private static readonly HashSet < string > s_nounExclusionList = new HashSet < string >
21
- {
20
+ private static readonly HashSet < string > s_nounExclusionList = new ( )
21
+ {
22
22
// PowerShellGet v2 nouns
23
23
"CredsFromCredentialProvider" ,
24
24
"DscResource" ,
@@ -36,8 +36,8 @@ internal static class CommandHelpers
36
36
} ;
37
37
38
38
// This is used when a noun exists in multiple modules (for example, "Command" is used in Microsoft.PowerShell.Core and also PowerShellGet)
39
- private static readonly HashSet < string > s_cmdletExclusionList = new HashSet < string >
40
- {
39
+ private static readonly HashSet < string > s_cmdletExclusionList = new ( )
40
+ {
41
41
// Commands in PowerShellGet with conflicting nouns
42
42
"Find-Command" ,
43
43
"Find-Module" ,
@@ -49,17 +49,17 @@ internal static class CommandHelpers
49
49
"Update-ModuleManifest" ,
50
50
} ;
51
51
52
- private static readonly ConcurrentDictionary < string , CommandInfo > s_commandInfoCache =
53
- new ConcurrentDictionary < string , CommandInfo > ( ) ;
54
-
55
- private static readonly ConcurrentDictionary < string , string > s_synopsisCache =
56
- new ConcurrentDictionary < string , string > ( ) ;
52
+ private static readonly ConcurrentDictionary < string , CommandInfo > s_commandInfoCache = new ( ) ;
53
+ private static readonly ConcurrentDictionary < string , string > s_synopsisCache = new ( ) ;
54
+ private static readonly ConcurrentDictionary < string , List < string > > s_cmdletToAliasCache = new ( System . StringComparer . OrdinalIgnoreCase ) ;
55
+ private static readonly ConcurrentDictionary < string , string > s_aliasToCmdletCache = new ( System . StringComparer . OrdinalIgnoreCase ) ;
57
56
58
57
/// <summary>
59
58
/// Gets the CommandInfo instance for a command with a particular name.
60
59
/// </summary>
61
60
/// <param name="commandName">The name of the command.</param>
62
- /// <param name="powerShellContext">The PowerShellContext to use for running Get-Command.</param>
61
+ /// <param name="currentRunspace">The current runspace.</param>
62
+ /// <param name="executionService">The execution service.</param>
63
63
/// <returns>A CommandInfo object with details about the specified command.</returns>
64
64
public static async Task < CommandInfo > GetCommandInfoAsync (
65
65
string commandName ,
@@ -97,7 +97,11 @@ public static async Task<CommandInfo> GetCommandInfoAsync(
97
97
. AddArgument ( commandName )
98
98
. AddParameter ( "ErrorAction" , "Ignore" ) ;
99
99
100
- CommandInfo commandInfo = ( await executionService . ExecutePSCommandAsync < CommandInfo > ( command , CancellationToken . None ) . ConfigureAwait ( false ) ) . FirstOrDefault ( ) ;
100
+ IReadOnlyList < CommandInfo > results = await executionService
101
+ . ExecutePSCommandAsync < CommandInfo > ( command , CancellationToken . None )
102
+ . ConfigureAwait ( false ) ;
103
+
104
+ CommandInfo commandInfo = results . Count > 0 ? results [ 0 ] : null ;
101
105
102
106
// Only cache CmdletInfos since they're exposed in binaries they are likely to not change throughout the session.
103
107
if ( commandInfo ? . CommandType == CommandTypes . Cmdlet )
@@ -112,8 +116,8 @@ public static async Task<CommandInfo> GetCommandInfoAsync(
112
116
/// Gets the command's "Synopsis" documentation section.
113
117
/// </summary>
114
118
/// <param name="commandInfo">The CommandInfo instance for the command.</param>
115
- /// <param name="executionService">The PowerShellContext to use for getting command documentation.</param>
116
- /// <returns></returns>
119
+ /// <param name="executionService">The exeuction service to use for getting command documentation.</param>
120
+ /// <returns>The synopsis. </returns>
117
121
public static async Task < string > GetCommandSynopsisAsync (
118
122
CommandInfo commandInfo ,
119
123
IInternalPowerShellExecutionService executionService )
@@ -146,13 +150,13 @@ public static async Task<string> GetCommandSynopsisAsync(
146
150
. AddParameter ( "Online" , false )
147
151
. AddParameter ( "ErrorAction" , "Ignore" ) ;
148
152
149
- IReadOnlyList < PSObject > results = await executionService . ExecutePSCommandAsync < PSObject > ( command , CancellationToken . None ) . ConfigureAwait ( false ) ;
150
- PSObject helpObject = results . FirstOrDefault ( ) ;
153
+ IReadOnlyList < PSObject > results = await executionService
154
+ . ExecutePSCommandAsync < PSObject > ( command , CancellationToken . None )
155
+ . ConfigureAwait ( false ) ;
151
156
152
157
// Extract the synopsis string from the object
153
- string synopsisString =
154
- ( string ) helpObject ? . Properties [ "synopsis" ] . Value ??
155
- string . Empty ;
158
+ PSObject helpObject = results . Count > 0 ? results [ 0 ] : null ;
159
+ string synopsisString = ( string ) helpObject ? . Properties [ "synopsis" ] . Value ?? string . Empty ;
156
160
157
161
// Only cache cmdlet infos because since they're exposed in binaries, the can never change throughout the session.
158
162
if ( commandInfo . CommandType == CommandTypes . Cmdlet )
@@ -168,5 +172,39 @@ public static async Task<string> GetCommandSynopsisAsync(
168
172
169
173
return synopsisString ;
170
174
}
175
+
176
+ /// <summary>
177
+ /// Gets all aliases found in the runspace
178
+ /// </summary>
179
+ /// <param name="executionService"></param>
180
+ public static async Task < ( Dictionary < string , List < string > > , Dictionary < string , string > ) > GetAliasesAsync ( IInternalPowerShellExecutionService executionService )
181
+ {
182
+ Validate . IsNotNull ( nameof ( executionService ) , executionService ) ;
183
+
184
+ IEnumerable < CommandInfo > aliases = await executionService . ExecuteDelegateAsync < IEnumerable < CommandInfo > > (
185
+ nameof ( GetAliasesAsync ) ,
186
+ Execution . ExecutionOptions . Default ,
187
+ ( pwsh , _ ) =>
188
+ {
189
+ CommandInvocationIntrinsics invokeCommand = pwsh . Runspace . SessionStateProxy . InvokeCommand ;
190
+ return invokeCommand . GetCommands ( "*" , CommandTypes . Alias , nameIsPattern : true ) ;
191
+ } ,
192
+ CancellationToken . None ) . ConfigureAwait ( false ) ;
193
+
194
+ foreach ( AliasInfo aliasInfo in aliases )
195
+ {
196
+ // TODO: When we move to netstandard2.1, we can use another overload which generates
197
+ // static delegates and thus reduces allocations.
198
+ s_cmdletToAliasCache . AddOrUpdate (
199
+ aliasInfo . Definition ,
200
+ ( _ ) => new List < string > { aliasInfo . Name } ,
201
+ ( _ , v ) => { v . Add ( aliasInfo . Name ) ; return v ; } ) ;
202
+
203
+ s_aliasToCmdletCache . TryAdd ( aliasInfo . Name , aliasInfo . Definition ) ;
204
+ }
205
+
206
+ return ( new Dictionary < string , List < string > > ( s_cmdletToAliasCache ) ,
207
+ new Dictionary < string , string > ( s_aliasToCmdletCache ) ) ;
208
+ }
171
209
}
172
210
}
0 commit comments