11
11
using System . Management . Automation . Remoting ;
12
12
using System . Management . Automation . Runspaces ;
13
13
using System . Reflection ;
14
+ using System . Runtime . InteropServices ;
14
15
using System . Text ;
15
16
using System . Threading ;
16
17
using System . Threading . Tasks ;
@@ -30,7 +31,7 @@ namespace Microsoft.PowerShell.EditorServices.Services
30
31
/// Handles nested PowerShell prompts and also manages execution of
31
32
/// commands whether inside or outside of the debugger.
32
33
/// </summary>
33
- internal class PowerShellContextService : IHostSupportsInteractiveSession
34
+ internal class PowerShellContextService : IHostSupportsInteractiveSession
34
35
{
35
36
// This is a default that can be overriden at runtime by the user or tests.
36
37
private static string s_bundledModulePath = Path . GetFullPath ( Path . Combine (
@@ -45,6 +46,10 @@ internal class PowerShellContextService : IHostSupportsInteractiveSession
45
46
"Commands" ,
46
47
"PowerShellEditorServices.Commands.psd1" ) ) ;
47
48
49
+ private static string s_psReadLineModulePath => Path . GetFullPath ( Path . Combine (
50
+ s_bundledModulePath ,
51
+ "PSReadLine" ) ) ;
52
+
48
53
private static readonly Action < Runspace , ApartmentState > s_runspaceApartmentStateSetter ;
49
54
private static readonly PropertyInfo s_writeStreamProperty ;
50
55
private static readonly object s_errorStreamValue ;
@@ -180,17 +185,17 @@ public RunspaceDetails CurrentRunspace
180
185
public PowerShellContextService (
181
186
ILogger logger ,
182
187
OmniSharp . Extensions . LanguageServer . Protocol . Server . ILanguageServerFacade languageServer ,
183
- bool isPSReadLineEnabled )
188
+ HostStartupInfo hostStartupInfo )
184
189
{
185
190
logger . LogTrace ( "Instantiating PowerShellContextService and adding event handlers" ) ;
186
191
_languageServer = languageServer ;
187
192
this . logger = logger ;
188
- this . isPSReadLineEnabled = isPSReadLineEnabled ;
193
+ this . isPSReadLineEnabled = hostStartupInfo . ConsoleReplEnabled
194
+ && ! hostStartupInfo . UsesLegacyReadLine ;
189
195
190
196
RunspaceChanged += PowerShellContext_RunspaceChangedAsync ;
191
197
ExecutionStatusChanged += PowerShellContext_ExecutionStatusChangedAsync ;
192
198
}
193
-
194
199
[ SuppressMessage ( "Design" , "CA1062:Validate arguments of public methods" , Justification = "Checked by Validate call" ) ]
195
200
public static PowerShellContextService Create (
196
201
ILoggerFactory factory ,
@@ -201,24 +206,14 @@ public static PowerShellContextService Create(
201
206
202
207
Validate . IsNotNull ( nameof ( hostStartupInfo ) , hostStartupInfo ) ;
203
208
204
- // Respect a user provided bundled module path.
205
- if ( Directory . Exists ( hostStartupInfo . BundledModulePath ) )
206
- {
207
- logger . LogTrace ( $ "Using new bundled module path: { hostStartupInfo . BundledModulePath } ") ;
208
- s_bundledModulePath = hostStartupInfo . BundledModulePath ;
209
- }
210
-
211
- bool shouldUsePSReadLine = hostStartupInfo . ConsoleReplEnabled
212
- && ! hostStartupInfo . UsesLegacyReadLine ;
213
-
214
209
var powerShellContext = new PowerShellContextService (
215
210
logger ,
216
211
languageServer ,
217
- shouldUsePSReadLine ) ;
212
+ hostStartupInfo ) ;
218
213
219
214
EditorServicesPSHostUserInterface hostUserInterface =
220
215
hostStartupInfo . ConsoleReplEnabled
221
- ? ( EditorServicesPSHostUserInterface ) new TerminalPSHostUserInterface ( powerShellContext , hostStartupInfo . PSHost , logger )
216
+ ? ( EditorServicesPSHostUserInterface ) new TerminalPSHostUserInterface ( powerShellContext , hostStartupInfo . PSHost , logger )
222
217
: new ProtocolPSHostUserInterface ( languageServer , powerShellContext , logger ) ;
223
218
224
219
EditorServicesPSHost psHost =
@@ -230,26 +225,7 @@ public static PowerShellContextService Create(
230
225
231
226
logger . LogTrace ( "Creating initial PowerShell runspace" ) ;
232
227
Runspace initialRunspace = PowerShellContextService . CreateRunspace ( psHost , hostStartupInfo . InitialSessionState ) ;
233
- powerShellContext . Initialize ( hostStartupInfo . ProfilePaths , initialRunspace , true , hostUserInterface ) ;
234
- powerShellContext . ImportCommandsModuleAsync ( ) ;
235
-
236
- // TODO: This can be moved to the point after the $psEditor object
237
- // gets initialized when that is done earlier than LanguageServer.Initialize
238
- foreach ( string module in hostStartupInfo . AdditionalModules )
239
- {
240
- var command =
241
- new PSCommand ( )
242
- . AddCommand ( "Microsoft.PowerShell.Core\\ Import-Module" )
243
- . AddParameter ( "Name" , module ) ;
244
-
245
- #pragma warning disable CS4014
246
- // This call queues the loading on the pipeline thread, so no need to await
247
- powerShellContext . ExecuteCommandAsync < PSObject > (
248
- command ,
249
- sendOutputToHost : false ,
250
- sendErrorToHost : true ) ;
251
- #pragma warning restore CS4014
252
- }
228
+ powerShellContext . Initialize ( hostStartupInfo , initialRunspace , true , hostUserInterface ) ;
253
229
254
230
return powerShellContext ;
255
231
}
@@ -311,7 +287,7 @@ public static Runspace CreateRunspace(PSHost psHost, InitialSessionState initial
311
287
/// <param name="ownsInitialRunspace">If true, the PowerShellContext owns this runspace.</param>
312
288
/// <param name="consoleHost">An IHostOutput implementation. Optional.</param>
313
289
public void Initialize (
314
- ProfilePathInfo profilePaths ,
290
+ HostStartupInfo hostStartupInfo ,
315
291
Runspace initialRunspace ,
316
292
bool ownsInitialRunspace ,
317
293
IHostOutput consoleHost )
@@ -342,7 +318,12 @@ public void Initialize(
342
318
RunspaceContext . Original ,
343
319
connectionString : null ) ;
344
320
this . CurrentRunspace = this . initialRunspace ;
345
-
321
+ // Respect a user provided bundled module path.
322
+ if ( Directory . Exists ( hostStartupInfo . BundledModulePath ) )
323
+ {
324
+ logger . LogTrace ( $ "Using new bundled module path: { hostStartupInfo . BundledModulePath } ") ;
325
+ s_bundledModulePath = hostStartupInfo . BundledModulePath ;
326
+ }
346
327
// Write out the PowerShell version for tracking purposes
347
328
this . logger . LogInformation ( $ "PowerShell Version: { this . LocalPowerShellVersion . Version } , Edition: { this . LocalPowerShellVersion . Edition } ") ;
348
329
@@ -365,7 +346,7 @@ public void Initialize(
365
346
this . ConfigureRunspaceCapabilities ( this . CurrentRunspace ) ;
366
347
367
348
// Set the $profile variable in the runspace
368
- this . profilePaths = profilePaths ;
349
+ this . profilePaths = hostStartupInfo . ProfilePaths ;
369
350
if ( profilePaths != null )
370
351
{
371
352
this . SetProfileVariableInCurrentRunspace ( profilePaths ) ;
@@ -399,10 +380,47 @@ public void Initialize(
399
380
this . ConsoleReader ,
400
381
this . versionSpecificOperations ) ;
401
382
this . InvocationEventQueue = InvocationEventQueue . Create ( this , this . PromptNest ) ;
383
+ this . ImportCommandsModuleAsync ( ) . GetAwaiter ( ) . GetResult ( ) ;
384
+ if ( isPSReadLineEnabled )
385
+ {
386
+ this . ImportPSReadLine2ModuleAsync ( ) . GetAwaiter ( ) . GetResult ( ) ;
387
+ }
388
+ // TODO: This can be moved to the point after the $psEditor object
389
+ // gets initialized when that is done earlier than LanguageServer.Initialize
390
+ foreach ( string module in hostStartupInfo . AdditionalModules )
391
+ {
392
+ var command =
393
+ new PSCommand ( )
394
+ . AddCommand ( "Microsoft.PowerShell.Core\\ Import-Module" )
395
+ . AddParameter ( "Name" , module ) ;
396
+
397
+ #pragma warning disable CS4014
398
+ // This call queues the loading on the pipeline thread, so no need to await
399
+ this . ExecuteCommandAsync < PSObject > (
400
+ command ,
401
+ sendOutputToHost : false ,
402
+ sendErrorToHost : true ) . GetAwaiter ( ) . GetResult ( ) ;
403
+ #pragma warning restore CS4014
404
+ }
405
+
406
+
407
+ // Import the PowerShellEditorServices.Commands module into the runspace.
408
+ this . ImportModuleAsync ( s_commandsModulePath ) . GetAwaiter ( ) . GetResult ( ) ;
409
+ if ( isPSReadLineEnabled )
410
+ {
411
+ // Imports the PSReadLine2 module into the runspace.
412
+ ImportModuleAsync ( s_psReadLineModulePath ) . GetAwaiter ( ) . GetResult ( ) ;
413
+ }
414
+ // TODO: This can be moved to the point after the $psEditor object
415
+ // gets initialized when that is done earlier than LanguageServer.Initialize
416
+ foreach ( string module in hostStartupInfo . AdditionalModules )
417
+ {
418
+ this . ImportModuleAsync ( module ) . GetAwaiter ( ) . GetResult ( ) ;
419
+ }
402
420
403
421
if ( powerShellVersion . Major >= 5 &&
404
422
this . isPSReadLineEnabled &&
405
- PSReadLinePromptContext . TryGetPSReadLineProxy ( logger , initialRunspace , s_bundledModulePath , out PSReadLineProxy proxy ) )
423
+ PSReadLinePromptContext . TryGetPSReadLineProxy ( logger , out PSReadLineProxy proxy ) )
406
424
{
407
425
this . PromptContext = new PSReadLinePromptContext (
408
426
this ,
@@ -414,24 +432,18 @@ public void Initialize(
414
432
{
415
433
this . PromptContext = new LegacyReadLineContext ( this ) ;
416
434
}
417
-
418
435
// Finally, restore the runspace's execution policy to the user's policy instead of
419
436
// Bypass.
420
437
this . RestoreExecutionPolicy ( ) ;
421
438
}
422
439
423
- /// <summary>
424
- /// Imports the PowerShellEditorServices.Commands module into
425
- /// the runspace. This method will be moved somewhere else soon.
426
- /// </summary>
427
- /// <returns></returns>
428
- public Task ImportCommandsModuleAsync ( )
440
+ public Task ImportModuleAsync ( string path )
429
441
{
430
- this . logger . LogTrace ( $ "Importing PowershellEditorServices commands from { s_commandsModulePath } ") ;
442
+ this . logger . LogTrace ( $ "Importing PowershellEditorServices commands from { path } ") ;
431
443
432
444
PSCommand importCommand = new PSCommand ( )
433
445
. AddCommand ( "Import-Module" )
434
- . AddArgument ( s_commandsModulePath ) ;
446
+ . AddArgument ( path ) ;
435
447
436
448
return this . ExecuteCommandAsync < PSObject > ( importCommand , sendOutputToHost : false , sendErrorToHost : false ) ;
437
449
}
@@ -485,7 +497,7 @@ private void CleanupRunspace(RunspaceDetails runspaceDetails)
485
497
/// <returns>A RunspaceHandle instance that gives access to the session's runspace.</returns>
486
498
public Task < RunspaceHandle > GetRunspaceHandleAsync ( )
487
499
{
488
- return this . GetRunspaceHandleImplAsync ( isReadLine : false , CancellationToken . None ) ;
500
+ return this . GetRunspaceHandleImplAsync ( CancellationToken . None , isReadLine : false ) ;
489
501
}
490
502
491
503
/// <summary>
@@ -497,7 +509,7 @@ public Task<RunspaceHandle> GetRunspaceHandleAsync()
497
509
/// <returns>A RunspaceHandle instance that gives access to the session's runspace.</returns>
498
510
public Task < RunspaceHandle > GetRunspaceHandleAsync ( CancellationToken cancellationToken )
499
511
{
500
- return this . GetRunspaceHandleImplAsync ( isReadLine : false , cancellationToken ) ;
512
+ return this . GetRunspaceHandleImplAsync ( cancellationToken , isReadLine : false ) ;
501
513
}
502
514
503
515
/// <summary>
@@ -994,7 +1006,7 @@ public Task<IEnumerable<object>> ExecuteScriptStringAsync(
994
1006
Validate . IsNotNull ( nameof ( scriptString ) , scriptString ) ;
995
1007
996
1008
PSCommand command = null ;
997
- if ( CurrentRunspace . Runspace . SessionStateProxy . LanguageMode != PSLanguageMode . FullLanguage )
1009
+ if ( CurrentRunspace . Runspace . SessionStateProxy . LanguageMode != PSLanguageMode . FullLanguage )
998
1010
{
999
1011
try
1000
1012
{
@@ -1009,7 +1021,7 @@ public Task<IEnumerable<object>> ExecuteScriptStringAsync(
1009
1021
}
1010
1022
1011
1023
// fall back to old behavior
1012
- if ( command == null )
1024
+ if ( command == null )
1013
1025
{
1014
1026
command = new PSCommand ( ) . AddScript ( scriptString . Trim ( ) ) ;
1015
1027
}
@@ -1415,12 +1427,12 @@ public void Close()
1415
1427
1416
1428
private Task < RunspaceHandle > GetRunspaceHandleAsync ( bool isReadLine )
1417
1429
{
1418
- return this . GetRunspaceHandleImplAsync ( isReadLine , CancellationToken . None ) ;
1430
+ return this . GetRunspaceHandleImplAsync ( CancellationToken . None , isReadLine ) ;
1419
1431
}
1420
1432
1421
- private Task < RunspaceHandle > GetRunspaceHandleImplAsync ( bool isReadLine , CancellationToken cancellationToken )
1433
+ private Task < RunspaceHandle > GetRunspaceHandleImplAsync ( CancellationToken cancellationToken , bool isReadLine )
1422
1434
{
1423
- return this . PromptNest . GetRunspaceHandleAsync ( isReadLine , cancellationToken ) ;
1435
+ return this . PromptNest . GetRunspaceHandleAsync ( cancellationToken , isReadLine ) ;
1424
1436
}
1425
1437
1426
1438
private ExecutionTarget GetExecutionTarget ( ExecutionOptions options = null )
@@ -1707,7 +1719,7 @@ internal static string QuoteEscapeString(string escapedPath)
1707
1719
internal static string WildcardEscapePath ( string path , bool escapeSpaces = false )
1708
1720
{
1709
1721
var sb = new StringBuilder ( ) ;
1710
- for ( int i = 0 ; i < path . Length ; i ++ )
1722
+ for ( int i = 0 ; i < path . Length ; i ++ )
1711
1723
{
1712
1724
char curr = path [ i ] ;
1713
1725
switch ( curr )
@@ -1760,7 +1772,7 @@ internal static string UnescapeWildcardEscapedPath(string wildcardEscapedPath)
1760
1772
}
1761
1773
1762
1774
var sb = new StringBuilder ( wildcardEscapedPath . Length ) ;
1763
- for ( int i = 0 ; i < wildcardEscapedPath . Length ; i ++ )
1775
+ for ( int i = 0 ; i < wildcardEscapedPath . Length ; i ++ )
1764
1776
{
1765
1777
// If we see a backtick perform a lookahead
1766
1778
char curr = wildcardEscapedPath [ i ] ;
@@ -2360,7 +2372,7 @@ private static IEnumerable<string> GetLoadableProfilePaths(ProfilePathInfo profi
2360
2372
yield break ;
2361
2373
}
2362
2374
2363
- foreach ( string path in new [ ] { profilePaths . AllUsersAllHosts , profilePaths . AllUsersCurrentHost , profilePaths . CurrentUserAllHosts , profilePaths . CurrentUserCurrentHost } )
2375
+ foreach ( string path in new [ ] { profilePaths . AllUsersAllHosts , profilePaths . AllUsersCurrentHost , profilePaths . CurrentUserAllHosts , profilePaths . CurrentUserCurrentHost } )
2364
2376
{
2365
2377
if ( path != null && File . Exists ( path ) )
2366
2378
{
0 commit comments