Skip to content

Commit b83a7a8

Browse files
committed
Merge pull request #51 from PowerShell/daviwil/0.2.0
Bug fixes and improvements for 0.2.0
2 parents dfc0f22 + 33f47ae commit b83a7a8

15 files changed

+311
-119
lines changed

appveyor.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: 0.1.0.{build}
1+
version: 0.2.0.{build}
22
os: Unstable
33
configuration: Release
44
clone_depth: 10
@@ -10,7 +10,7 @@ branches:
1010
assembly_info:
1111
patch: true
1212
file: '**\AssemblyInfo.*'
13-
assembly_version: '0.1.0' # This version number should always have 0 for the last section
13+
assembly_version: '0.2.0' # This version number should always have 0 for the last section
1414
assembly_file_version: '{version}'
1515
assembly_informational_version: '{version}'
1616

src/PowerShellEditorServices.Host/DebugAdapter.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ protected async Task HandleLaunchRequest(
101101
// Execute the given PowerShell script and send the response.
102102
// Note that we aren't waiting for execution to complete here
103103
// because the debugger could stop while the script executes.
104-
editorSession.powerShellContext
104+
editorSession.PowerShellContext
105105
.ExecuteScriptAtPath(launchParams.Program)
106106
.ContinueWith(
107107
async (t) =>
@@ -141,15 +141,15 @@ protected Task HandleDisconnectRequest(
141141
if (e.NewSessionState == PowerShellContextState.Ready)
142142
{
143143
await requestContext.SendResult(null);
144-
editorSession.powerShellContext.SessionStateChanged -= handler;
144+
editorSession.PowerShellContext.SessionStateChanged -= handler;
145145

146146
// TODO: Find a way to exit more gracefully!
147147
Environment.Exit(0);
148148
}
149149
};
150150

151-
editorSession.powerShellContext.SessionStateChanged += handler;
152-
editorSession.powerShellContext.AbortExecution();
151+
editorSession.PowerShellContext.SessionStateChanged += handler;
152+
editorSession.PowerShellContext.AbortExecution();
153153

154154
return Task.FromResult(true);
155155
}

src/PowerShellEditorServices.Host/LanguageServer.cs

Lines changed: 78 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ internal class LanguageServer : IMessageProcessor
2525
private static CancellationTokenSource existingRequestCancellation;
2626

2727
private MessageDispatcher<EditorSession> messageDispatcher;
28+
private LanguageServerSettings currentSettings = new LanguageServerSettings();
2829

2930
public LanguageServer()
3031
{
@@ -42,6 +43,7 @@ public void Initialize()
4243
this.AddEventHandler(DidOpenTextDocumentNotification.Type, this.HandleDidOpenTextDocumentNotification);
4344
this.AddEventHandler(DidCloseTextDocumentNotification.Type, this.HandleDidCloseTextDocumentNotification);
4445
this.AddEventHandler(DidChangeTextDocumentNotification.Type, this.HandleDidChangeTextDocumentNotification);
46+
this.AddEventHandler(DidChangeConfigurationNotification<SettingsWrapper>.Type, this.HandleDidChangeConfigurationNotification);
4547

4648
this.AddRequestHandler(DefinitionRequest.Type, this.HandleDefinitionRequest);
4749
this.AddRequestHandler(ReferencesRequest.Type, this.HandleReferencesRequest);
@@ -94,6 +96,9 @@ protected async Task HandleInitializeRequest(
9496
EditorSession editorSession,
9597
RequestContext<InitializeResult, InitializeError> requestContext)
9698
{
99+
// Grab the workspace path from the parameters
100+
editorSession.Workspace.WorkspacePath = initializeParams.RootPath;
101+
97102
await requestContext.SendResult(
98103
new InitializeResult
99104
{
@@ -130,20 +135,19 @@ protected Task HandleShutdownRequest(
130135
}
131136

132137
protected async Task HandleShowOnlineHelpRequest(
133-
object helpParams,
138+
string helpParams,
134139
EditorSession editorSession,
135140
RequestContext<object, object> requestContext)
136141
{
137-
var psCommand = new PSCommand();
138-
139142
if (helpParams == null) { helpParams = "get-help"; }
140143

141-
var script = string.Format("get-help {0} -Online", helpParams);
142-
143-
psCommand.AddScript(script);
144+
var psCommand = new PSCommand();
145+
psCommand.AddCommand("Get-Help");
146+
psCommand.AddArgument(helpParams);
147+
psCommand.AddParameter("Online");
144148

145-
var result = await editorSession.powerShellContext.ExecuteCommand<object>(
146-
psCommand);
149+
await editorSession.PowerShellContext.ExecuteCommand<object>(
150+
psCommand);
147151

148152
await requestContext.SendResult(null);
149153
}
@@ -226,6 +230,36 @@ protected Task HandleDidChangeTextDocumentNotification(
226230
return Task.FromResult(true);
227231
}
228232

233+
protected async Task HandleDidChangeConfigurationNotification(
234+
DidChangeConfigurationParams<SettingsWrapper> configChangeParams,
235+
EditorSession editorSession,
236+
EventContext eventContext)
237+
{
238+
bool oldScriptAnalysisEnabled =
239+
this.currentSettings.ScriptAnalysis.Enable.HasValue;
240+
241+
this.currentSettings.Update(
242+
configChangeParams.Settings.Powershell);
243+
244+
if (oldScriptAnalysisEnabled != this.currentSettings.ScriptAnalysis.Enable)
245+
{
246+
// If the user just turned off script analysis, send a diagnostics
247+
// event to clear the analysis markers that they already have
248+
if (!this.currentSettings.ScriptAnalysis.Enable.Value)
249+
{
250+
ScriptFileMarker[] emptyAnalysisDiagnostics = new ScriptFileMarker[0];
251+
252+
foreach (var scriptFile in editorSession.Workspace.GetOpenedFiles())
253+
{
254+
await PublishScriptDiagnostics(
255+
scriptFile,
256+
emptyAnalysisDiagnostics,
257+
eventContext);
258+
}
259+
}
260+
}
261+
}
262+
229263
protected async Task HandleDefinitionRequest(
230264
TextDocumentPosition textDocumentPosition,
231265
EditorSession editorSession,
@@ -387,21 +421,18 @@ protected async Task HandleCompletionResolveRequest(
387421
if (completionItem.Kind == CompletionItemKind.Function)
388422
{
389423
RunspaceHandle runspaceHandle =
390-
await editorSession.powerShellContext.GetRunspaceHandle();
424+
await editorSession.PowerShellContext.GetRunspaceHandle();
391425

392426
// Get the documentation for the function
393427
CommandInfo commandInfo =
394428
CommandHelpers.GetCommandInfo(
395429
completionItem.Label,
396430
runspaceHandle.Runspace);
397431

398-
if (commandInfo != null)
399-
{
400-
completionItem.Documentation =
401-
CommandHelpers.GetCommandSynopsis(
402-
commandInfo,
403-
runspaceHandle.Runspace);
404-
}
432+
completionItem.Documentation =
433+
CommandHelpers.GetCommandSynopsis(
434+
commandInfo,
435+
runspaceHandle.Runspace);
405436

406437
runspaceHandle.Dispose();
407438
}
@@ -744,6 +775,12 @@ private Task RunScriptDiagnostics(
744775
EditorSession editorSession,
745776
EventContext eventContext)
746777
{
778+
if (!this.currentSettings.ScriptAnalysis.Enable.Value)
779+
{
780+
// If the user has disabled script analysis, skip it entirely
781+
return TaskConstants.Completed;
782+
}
783+
747784
// If there's an existing task, attempt to cancel it
748785
try
749786
{
@@ -827,24 +864,36 @@ private static async Task DelayThenInvokeDiagnostics(
827864

828865
var allMarkers = scriptFile.SyntaxMarkers.Concat(semanticMarkers);
829866

830-
// Always send syntax and semantic errors. We want to
831-
// make sure no out-of-date markers are being displayed.
832-
await eventContext.SendEvent(
833-
PublishDiagnosticsNotification.Type,
834-
new PublishDiagnosticsNotification
835-
{
836-
Uri = scriptFile.ClientFilePath,
837-
Diagnostics =
838-
allMarkers
839-
.Select(GetDiagnosticFromMarker)
840-
.ToArray()
841-
});
842-
867+
await PublishScriptDiagnostics(
868+
scriptFile,
869+
semanticMarkers,
870+
eventContext);
843871
}
844872

845873
Logger.Write(LogLevel.Verbose, "Analysis complete.");
846874
}
847875

876+
private async static Task PublishScriptDiagnostics(
877+
ScriptFile scriptFile,
878+
ScriptFileMarker[] semanticMarkers,
879+
EventContext eventContext)
880+
{
881+
var allMarkers = scriptFile.SyntaxMarkers.Concat(semanticMarkers);
882+
883+
// Always send syntax and semantic errors. We want to
884+
// make sure no out-of-date markers are being displayed.
885+
await eventContext.SendEvent(
886+
PublishDiagnosticsNotification.Type,
887+
new PublishDiagnosticsNotification
888+
{
889+
Uri = scriptFile.ClientFilePath,
890+
Diagnostics =
891+
allMarkers
892+
.Select(GetDiagnosticFromMarker)
893+
.ToArray()
894+
});
895+
}
896+
848897
private static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMarker)
849898
{
850899
return new Diagnostic
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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+
namespace Microsoft.PowerShell.EditorServices.Host
7+
{
8+
internal class LanguageServerSettings
9+
{
10+
public ScriptAnalysisSettings ScriptAnalysis { get; set; }
11+
12+
public LanguageServerSettings()
13+
{
14+
this.ScriptAnalysis = new ScriptAnalysisSettings();
15+
}
16+
17+
public void Update(LanguageServerSettings settings)
18+
{
19+
if (settings != null)
20+
{
21+
this.ScriptAnalysis.Update(settings.ScriptAnalysis);
22+
}
23+
}
24+
}
25+
26+
internal class ScriptAnalysisSettings
27+
{
28+
public bool? Enable { get; set; }
29+
30+
public ScriptAnalysisSettings()
31+
{
32+
this.Enable = true;
33+
}
34+
35+
public void Update(ScriptAnalysisSettings settings)
36+
{
37+
if (settings != null)
38+
{
39+
this.Enable = settings.Enable;
40+
}
41+
}
42+
}
43+
44+
internal class SettingsWrapper
45+
{
46+
// NOTE: This property is capitalized as 'Powershell' because the
47+
// mode name sent from the client is written as 'powershell' and
48+
// JSON.net is using camelCasing.
49+
50+
public LanguageServerSettings Powershell { get; set; }
51+
}
52+
}

src/PowerShellEditorServices.Host/MessageLoop.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ async Task ListenForMessages()
129129
// Set up the PowerShell session
130130
this.editorSession = new EditorSession();
131131
this.editorSession.StartSession(this.consoleHost);
132-
this.editorSession.powerShellContext.OutputWritten += powerShellContext_OutputWritten;
132+
this.editorSession.PowerShellContext.OutputWritten += powerShellContext_OutputWritten;
133133

134134
if (this.runDebugAdapter)
135135
{

src/PowerShellEditorServices.Host/PowerShellEditorServices.Host.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<Compile Include="DebugAdapter.cs" />
6363
<Compile Include="IMessageProcessor.cs" />
6464
<Compile Include="LanguageServer.cs" />
65+
<Compile Include="LanguageServerSettings.cs" />
6566
<Compile Include="MessageLoop.cs" />
6667
<Compile Include="Program.cs" />
6768
<Compile Include="Properties\AssemblyInfo.cs" />
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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 DidChangeConfigurationNotification<TConfig>
11+
{
12+
public static readonly
13+
EventType<DidChangeConfigurationParams<TConfig>> Type =
14+
EventType<DidChangeConfigurationParams<TConfig>>.Create("workspace/didChangeConfiguration");
15+
}
16+
17+
public class DidChangeConfigurationParams<TConfig>
18+
{
19+
public TConfig Settings { get; set; }
20+
}
21+
}

src/PowerShellEditorServices.Protocol/LanguageServer/ShowOnlineHelpRequest.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace Microsoft.PowerShell.EditorServices.Protocol.LanguageServer
99
{
1010
public class ShowOnlineHelpRequest
1111
{
12-
public static readonly RequestType<object, object, object> Type = RequestType<object, object, object>.Create("showonlinehelp");
12+
public static readonly
13+
RequestType<string, object, object> Type =
14+
RequestType<string, object, object>.Create("powerShell/showOnlineHelp");
1315
}
1416
}

src/PowerShellEditorServices.Protocol/PowerShellEditorServices.Protocol.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
<Compile Include="DebugAdapter\V8MessageSerializer.cs" />
9090
<Compile Include="DebugAdapter\Variable.cs" />
9191
<Compile Include="DebugAdapter\VariablesRequest.cs" />
92+
<Compile Include="LanguageServer\Configuration.cs" />
9293
<Compile Include="LanguageServer\Definition.cs" />
9394
<Compile Include="LanguageServer\DocumentHighlight.cs" />
9495
<Compile Include="LanguageServer\Hover.cs" />

src/PowerShellEditorServices/Language/CommandHelpers.cs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,25 +52,31 @@ public static string GetCommandSynopsis(
5252

5353
PSObject helpObject = null;
5454

55-
using (PowerShell powerShell = PowerShell.Create())
56-
{
57-
powerShell.Runspace = runspace;
58-
powerShell.AddCommand("Get-Help");
59-
powerShell.AddArgument(commandInfo);
60-
helpObject = powerShell.Invoke<PSObject>().FirstOrDefault();
61-
}
62-
63-
if (helpObject != null)
55+
if (commandInfo != null &&
56+
(commandInfo.CommandType == CommandTypes.Cmdlet ||
57+
commandInfo.CommandType == CommandTypes.Function ||
58+
commandInfo.CommandType == CommandTypes.Filter))
6459
{
65-
// Extract the synopsis string from the object
66-
synopsisString =
67-
(string)helpObject.Properties["synopsis"].Value ??
68-
string.Empty;
60+
using (PowerShell powerShell = PowerShell.Create())
61+
{
62+
powerShell.Runspace = runspace;
63+
powerShell.AddCommand("Get-Help");
64+
powerShell.AddArgument(commandInfo);
65+
helpObject = powerShell.Invoke<PSObject>().FirstOrDefault();
66+
}
6967

70-
// Ignore the placeholder value for this field
71-
if (string.Equals(synopsisString, "SHORT DESCRIPTION", System.StringComparison.InvariantCultureIgnoreCase))
68+
if (helpObject != null)
7269
{
73-
synopsisString = string.Empty;
70+
// Extract the synopsis string from the object
71+
synopsisString =
72+
(string)helpObject.Properties["synopsis"].Value ??
73+
string.Empty;
74+
75+
// Ignore the placeholder value for this field
76+
if (string.Equals(synopsisString, "SHORT DESCRIPTION", System.StringComparison.InvariantCultureIgnoreCase))
77+
{
78+
synopsisString = string.Empty;
79+
}
7480
}
7581
}
7682

0 commit comments

Comments
 (0)