Skip to content

Commit 580742c

Browse files
committed
Merge pull request #59 from PowerShell/dfinke/expandAlias
Add "Expand Alias" support
2 parents dc740c0 + d758eda commit 580742c

File tree

5 files changed

+133
-61
lines changed

5 files changed

+133
-61
lines changed

src/PowerShellEditorServices.Host/LanguageServer.cs

+43-3
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public void Initialize()
5656
this.AddRequestHandler(WorkspaceSymbolRequest.Type, this.HandleWorkspaceSymbolRequest);
5757

5858
this.AddRequestHandler(ShowOnlineHelpRequest.Type, this.HandleShowOnlineHelpRequest);
59+
this.AddRequestHandler(ExpandAliasRequest.Type, this.HandleExpandAliasRequest);
5960

6061
this.AddRequestHandler(DebugAdapterMessages.EvaluateRequest.Type, this.HandleEvaluateRequest);
6162
}
@@ -152,6 +153,45 @@ await editorSession.PowerShellContext.ExecuteCommand<object>(
152153
await requestContext.SendResult(null);
153154
}
154155

156+
private async Task HandleExpandAliasRequest(
157+
string content,
158+
EditorSession editorSession,
159+
RequestContext<string, object> requestContext)
160+
{
161+
var script = @"
162+
function __Expand-Alias {
163+
164+
param($targetScript)
165+
166+
[ref]$errors=$null
167+
168+
$tokens = [System.Management.Automation.PsParser]::Tokenize($targetScript, $errors).Where({$_.type -eq 'command'}) |
169+
Sort Start -Descending
170+
171+
foreach ($token in $tokens) {
172+
$definition=(Get-Command ('`'+$token.Content) -CommandType Alias -ErrorAction SilentlyContinue).Definition
173+
174+
if($definition) {
175+
$lhs=$targetScript.Substring(0, $token.Start)
176+
$rhs=$targetScript.Substring($token.Start + $token.Length)
177+
178+
$targetScript=$lhs + $definition + $rhs
179+
}
180+
}
181+
182+
$targetScript
183+
}";
184+
var psCommand = new PSCommand();
185+
psCommand.AddScript(script);
186+
await editorSession.PowerShellContext.ExecuteCommand<PSObject>(psCommand);
187+
188+
psCommand = new PSCommand();
189+
psCommand.AddCommand("__Expand-Alias").AddArgument(content);
190+
var result = await editorSession.PowerShellContext.ExecuteCommand<string>(psCommand);
191+
192+
await requestContext.SendResult(result.First().ToString());
193+
}
194+
155195
protected Task HandleExitNotification(
156196
object exitParams,
157197
EditorSession editorSession,
@@ -235,7 +275,7 @@ protected async Task HandleDidChangeConfigurationNotification(
235275
EditorSession editorSession,
236276
EventContext eventContext)
237277
{
238-
bool oldScriptAnalysisEnabled =
278+
bool oldScriptAnalysisEnabled =
239279
this.currentSettings.ScriptAnalysis.Enable.HasValue;
240280

241281
this.currentSettings.Update(
@@ -887,8 +927,8 @@ await eventContext.SendEvent(
887927
new PublishDiagnosticsNotification
888928
{
889929
Uri = scriptFile.ClientFilePath,
890-
Diagnostics =
891-
allMarkers
930+
Diagnostics =
931+
allMarkers
892932
.Select(GetDiagnosticFromMarker)
893933
.ToArray()
894934
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
7+
8+
namespace Microsoft.PowerShell.EditorServices.Protocol.LanguageServer
9+
{
10+
public class ExpandAliasRequest
11+
{
12+
public static readonly
13+
RequestType<string, string, object> Type =
14+
RequestType<string, string, object>.Create("powerShell/expandAlias");
15+
}
16+
}

src/PowerShellEditorServices.Protocol/PowerShellEditorServices.Protocol.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
<Compile Include="LanguageServer\Configuration.cs" />
9393
<Compile Include="LanguageServer\Definition.cs" />
9494
<Compile Include="LanguageServer\DocumentHighlight.cs" />
95+
<Compile Include="LanguageServer\ExpandAliasRequest.cs" />
9596
<Compile Include="LanguageServer\Hover.cs" />
9697
<Compile Include="LanguageServer\ShowOnlineHelpRequest.cs" />
9798
<Compile Include="LanguageServer\SignatureHelp.cs" />

src/PowerShellEditorServices/Session/PowerShellContext.cs

+15-11
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ public Task<RunspaceHandle> GetRunspaceHandle()
166166
/// execution completes.
167167
/// </returns>
168168
public async Task<IEnumerable<TResult>> ExecuteCommand<TResult>(
169-
PSCommand psCommand,
169+
PSCommand psCommand,
170170
bool sendOutputToHost = false)
171171
{
172172
// If the debugger is active and the caller isn't on the pipeline
@@ -207,7 +207,7 @@ public async Task<IEnumerable<TResult>> ExecuteCommand<TResult>(
207207
this.debuggerStoppedTask != null)
208208
{
209209
Logger.Write(
210-
LogLevel.Verbose,
210+
LogLevel.Verbose,
211211
string.Format(
212212
"Attempting to execute nested pipeline command(s):\r\n\r\n{0}",
213213
GetStringForPSCommand(psCommand)));
@@ -231,7 +231,7 @@ public async Task<IEnumerable<TResult>> ExecuteCommand<TResult>(
231231
else
232232
{
233233
Logger.Write(
234-
LogLevel.Verbose,
234+
LogLevel.Verbose,
235235
string.Format(
236236
"Attempting to execute command(s):\r\n\r\n{0}",
237237
GetStringForPSCommand(psCommand)));
@@ -262,15 +262,19 @@ await Task.Factory.StartNew<IEnumerable<TResult>>(
262262

263263
if (this.powerShell.HadErrors)
264264
{
265-
// TODO: Find a good way to extract errors!
266-
Logger.Write(
267-
LogLevel.Error,
268-
"Execution completed with errors.");
265+
string errorMessage = "Execution completed with errors:\r\n\r\n";
266+
267+
foreach (var error in this.powerShell.Streams.Error)
268+
{
269+
errorMessage += error.ToString() + "\r\n";
270+
}
271+
272+
Logger.Write(LogLevel.Error, errorMessage);
269273
}
270274
else
271275
{
272276
Logger.Write(
273-
LogLevel.Verbose,
277+
LogLevel.Verbose,
274278
"Execution completed successfully.");
275279
}
276280

@@ -411,7 +415,7 @@ internal void ReleaseRunspaceHandle(RunspaceHandle runspaceHandle)
411415
if (!this.runspaceWaitQueue.IsEmpty)
412416
{
413417
this.currentRunspaceHandle = new RunspaceHandle(this.currentRunspace, this);
414-
dequeuedTask =
418+
dequeuedTask =
415419
this.runspaceWaitQueue.Dequeue(
416420
this.currentRunspaceHandle);
417421
}
@@ -442,7 +446,7 @@ private void OnSessionStateChanged(object sender, SessionStateChangedEventArgs e
442446
this.SessionState.ToString(),
443447
e.NewSessionState.ToString()));
444448

445-
this.SessionState = e.NewSessionState;
449+
this.SessionState = e.NewSessionState;
446450

447451
if (this.SessionStateChanged != null)
448452
{
@@ -557,7 +561,7 @@ private void SetExecutionPolicy(ExecutionPolicy desiredExecutionPolicy)
557561
currentPolicy = result.FirstOrDefault();
558562
}
559563

560-
if (desiredExecutionPolicy < currentPolicy ||
564+
if (desiredExecutionPolicy < currentPolicy ||
561565
desiredExecutionPolicy == ExecutionPolicy.Bypass ||
562566
currentPolicy == ExecutionPolicy.Undefined)
563567
{

test/PowerShellEditorServices.Test.Host/ScenarioTests.cs

+58-47
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ public class ScenarioTests : IDisposable
2020
{
2121
private int messageId = 0;
2222

23-
private LanguageServiceManager languageServiceManager =
23+
private LanguageServiceManager languageServiceManager =
2424
new LanguageServiceManager();
2525

26-
private MessageReader MessageReader
27-
{
28-
get { return this.languageServiceManager.MessageReader; }
26+
private MessageReader MessageReader
27+
{
28+
get { return this.languageServiceManager.MessageReader; }
2929
}
3030

3131
private MessageWriter MessageWriter
@@ -109,7 +109,7 @@ await this.SendRequest(
109109
Assert.Equal("string", consoleFileNameItem.Detail);
110110
}
111111

112-
[Fact(Skip="Skipped until variable documentation gathering is added back.")]
112+
[Fact(Skip = "Skipped until variable documentation gathering is added back.")]
113113
public async Task CompletesDetailOnVariableDocSuggestion()
114114
{
115115
//await this.SendOpenFileEvent("TestFiles\\CompleteFunctionName.ps1");
@@ -429,51 +429,62 @@ await this.SendRequestWithoutWait(
429429
Assert.Equal("stdout", outputEvent.Category);
430430
}
431431

432+
[Fact]
433+
public async Task ServiceExpandsAliases()
434+
{
435+
string expandedText =
436+
await this.SendRequest(
437+
ExpandAliasRequest.Type,
438+
"gci\r\npwd");
439+
440+
Assert.Equal("Get-ChildItem\r\nGet-Location", expandedText);
441+
}
442+
432443
[Fact]//(Skip = "Choice prompt functionality is currently in transition to a new model.")]
433444
public async Task ServiceExecutesReplCommandAndReceivesChoicePrompt()
434445
{
435446
// TODO: This test is removed until a new choice prompt strategy is determined.
436447

437-
// string choiceScript =
438-
// @"
439-
// $caption = ""Test Choice"";
440-
// $message = ""Make a selection"";
441-
// $choiceA = new-Object System.Management.Automation.Host.ChoiceDescription ""&A"",""A"";
442-
// $choiceB = new-Object System.Management.Automation.Host.ChoiceDescription ""&B"",""B"";
443-
// $choices = [System.Management.Automation.Host.ChoiceDescription[]]($choiceA,$choiceB);
444-
// $response = $host.ui.PromptForChoice($caption, $message, $choices, 1)
445-
// $response";
446-
447-
// await this.MessageWriter.WriteMessage(
448-
// new ReplExecuteRequest
449-
// {
450-
// Arguments = new ReplExecuteArgs
451-
// {
452-
// CommandString = choiceScript
453-
// }
454-
// });
455-
456-
// // Wait for the choice prompt event and check expected values
457-
// ReplPromptChoiceEvent replPromptChoiceEvent = this.WaitForMessage<ReplPromptChoiceEvent>();
458-
// Assert.Equal(1, replPromptChoiceEvent.Body.DefaultChoice);
459-
460-
// // Respond to the prompt event
461-
// await this.MessageWriter.WriteMessage(
462-
// new ReplPromptChoiceResponse
463-
// {
464-
// Body = new ReplPromptChoiceResponseBody
465-
// {
466-
// Choice = 0
467-
// }
468-
// });
469-
470-
// // Wait for the selection to appear as output
471-
// ReplWriteOutputEvent replWriteLineEvent = this.WaitForMessage<ReplWriteOutputEvent>();
472-
// Assert.Equal("0", replWriteLineEvent.Body.LineContents);
448+
// string choiceScript =
449+
// @"
450+
// $caption = ""Test Choice"";
451+
// $message = ""Make a selection"";
452+
// $choiceA = new-Object System.Management.Automation.Host.ChoiceDescription ""&A"",""A"";
453+
// $choiceB = new-Object System.Management.Automation.Host.ChoiceDescription ""&B"",""B"";
454+
// $choices = [System.Management.Automation.Host.ChoiceDescription[]]($choiceA,$choiceB);
455+
// $response = $host.ui.PromptForChoice($caption, $message, $choices, 1)
456+
// $response";
457+
458+
// await this.MessageWriter.WriteMessage(
459+
// new ReplExecuteRequest
460+
// {
461+
// Arguments = new ReplExecuteArgs
462+
// {
463+
// CommandString = choiceScript
464+
// }
465+
// });
466+
467+
// // Wait for the choice prompt event and check expected values
468+
// ReplPromptChoiceEvent replPromptChoiceEvent = this.WaitForMessage<ReplPromptChoiceEvent>();
469+
// Assert.Equal(1, replPromptChoiceEvent.Body.DefaultChoice);
470+
471+
// // Respond to the prompt event
472+
// await this.MessageWriter.WriteMessage(
473+
// new ReplPromptChoiceResponse
474+
// {
475+
// Body = new ReplPromptChoiceResponseBody
476+
// {
477+
// Choice = 0
478+
// }
479+
// });
480+
481+
// // Wait for the selection to appear as output
482+
// ReplWriteOutputEvent replWriteLineEvent = this.WaitForMessage<ReplWriteOutputEvent>();
483+
// Assert.Equal("0", replWriteLineEvent.Body.LineContents);
473484
}
474485

475486
private async Task<TResult> SendRequest<TParams, TResult, TError>(
476-
RequestType<TParams, TResult, TError> requestType,
487+
RequestType<TParams, TResult, TError> requestType,
477488
TParams requestParams)
478489
{
479490
await this.SendRequestWithoutWait(requestType, requestParams);
@@ -491,7 +502,7 @@ await this.MessageWriter.WriteMessage(
491502
this.messageId.ToString(),
492503
requestType.TypeName,
493504
JToken.FromObject(requestParams)));
494-
}
505+
}
495506

496507
private async Task SendEvent<TParams>(EventType<TParams> eventType, TParams eventParams)
497508
{
@@ -506,9 +517,9 @@ private async Task SendOpenFileEvent(string filePath, bool waitForDiagnostics =
506517
string fileContents = string.Join(Environment.NewLine, File.ReadAllLines(filePath));
507518

508519
await this.SendEvent(
509-
DidOpenTextDocumentNotification.Type,
510-
new DidOpenTextDocumentNotification()
511-
{
520+
DidOpenTextDocumentNotification.Type,
521+
new DidOpenTextDocumentNotification()
522+
{
512523
Uri = filePath,
513524
Text = fileContents
514525
});
@@ -535,7 +546,7 @@ private TParams WaitForEvent<TParams>(EventType<TParams> eventType)
535546
}
536547

537548
private TResult WaitForResponse<TParams, TResult, TError>(
538-
RequestType<TParams, TResult, TError> requestType,
549+
RequestType<TParams, TResult, TError> requestType,
539550
int expectedId)
540551
{
541552
// TODO: Integrate timeout!

0 commit comments

Comments
 (0)