9
9
using Microsoft . PowerShell . EditorServices . Protocol . MessageProtocol . Channel ;
10
10
using Microsoft . PowerShell . EditorServices . Session ;
11
11
using Microsoft . PowerShell . EditorServices . Utility ;
12
+ using Newtonsoft . Json . Linq ;
12
13
using System ;
13
14
using System . Collections . Generic ;
14
15
using System . IO ;
@@ -31,11 +32,18 @@ public class LanguageServer : LanguageServerBase
31
32
private LanguageServerEditorOperations editorOperations ;
32
33
private LanguageServerSettings currentSettings = new LanguageServerSettings ( ) ;
33
34
35
+ < << << << 2d 4012 eee01d844c3e2d46aa538aa348d63530b0
34
36
/// <param name="hostDetails">
35
37
/// Provides details about the host application.
36
38
/// </param>
37
39
public LanguageServer ( HostDetails hostDetails , ProfilePaths profilePaths )
38
40
: this ( hostDetails , profilePaths , new StdioServerChannel ( ) )
41
+ == == == =
42
+ private Dictionary < string , Dictionary < string , MarkerCorrection > > codeActionsPerFile =
43
+ new Dictionary < string , Dictionary < string , MarkerCorrection > > ( ) ;
44
+
45
+ public LanguageServer ( ) : this ( new StdioServerChannel ( ) )
46
+ >>> >>> > DRAFT: Initial "code actions" support
39
47
{
40
48
}
41
49
@@ -92,6 +100,7 @@ protected override void Initialize()
92
100
this . SetRequestHandler ( HoverRequest . Type , this . HandleHoverRequest ) ;
93
101
this . SetRequestHandler ( DocumentSymbolRequest . Type , this . HandleDocumentSymbolRequest ) ;
94
102
this . SetRequestHandler ( WorkspaceSymbolRequest . Type , this . HandleWorkspaceSymbolRequest ) ;
103
+ this . SetRequestHandler ( CodeActionRequest . Type , this . HandleCodeActionRequest ) ;
95
104
96
105
this . SetRequestHandler ( ShowOnlineHelpRequest . Type , this . HandleShowOnlineHelpRequest ) ;
97
106
this . SetRequestHandler ( ExpandAliasRequest . Type , this . HandleExpandAliasRequest ) ;
@@ -146,6 +155,7 @@ await requestContext.SendResult(
146
155
DocumentSymbolProvider = true ,
147
156
WorkspaceSymbolProvider = true ,
148
157
HoverProvider = true ,
158
+ CodeActionProvider = true ,
149
159
CompletionProvider = new CompletionOptions
150
160
{
151
161
ResolveProvider = true ,
@@ -226,17 +236,17 @@ function __Expand-Alias {
226
236
param($targetScript)
227
237
228
238
[ref]$errors=$null
229
-
230
- $tokens = [System.Management.Automation.PsParser]::Tokenize($targetScript, $errors).Where({$_.type -eq 'command'}) |
239
+
240
+ $tokens = [System.Management.Automation.PsParser]::Tokenize($targetScript, $errors).Where({$_.type -eq 'command'}) |
231
241
Sort Start -Descending
232
242
233
243
foreach ($token in $tokens) {
234
244
$definition=(Get-Command ('`'+$token.Content) -CommandType Alias -ErrorAction SilentlyContinue).Definition
235
245
236
- if($definition) {
246
+ if($definition) {
237
247
$lhs=$targetScript.Substring(0, $token.Start)
238
248
$rhs=$targetScript.Substring($token.Start + $token.Length)
239
-
249
+
240
250
$targetScript=$lhs + $definition + $rhs
241
251
}
242
252
}
@@ -346,13 +356,13 @@ protected async Task HandleDidChangeConfigurationNotification(
346
356
EventContext eventContext )
347
357
{
348
358
bool oldLoadProfiles = this . currentSettings . EnableProfileLoading ;
349
- bool oldScriptAnalysisEnabled =
359
+ bool oldScriptAnalysisEnabled =
350
360
this . currentSettings . ScriptAnalysis . Enable . HasValue ;
351
361
string oldScriptAnalysisSettingsPath =
352
362
this . currentSettings . ScriptAnalysis . SettingsPath ;
353
363
354
364
this . currentSettings . Update (
355
- configChangeParams . Settings . Powershell ,
365
+ configChangeParams . Settings . Powershell ,
356
366
this . editorSession . Workspace . WorkspacePath ) ;
357
367
358
368
if ( ! this . profilesLoaded &&
@@ -386,6 +396,7 @@ protected async Task HandleDidChangeConfigurationNotification(
386
396
await PublishScriptDiagnostics (
387
397
scriptFile ,
388
398
emptyAnalysisDiagnostics ,
399
+ this . codeActionsPerFile ,
389
400
eventContext ) ;
390
401
}
391
402
}
@@ -815,6 +826,35 @@ private bool IsQueryMatch(string query, string symbolName)
815
826
return symbolName . IndexOf ( query , StringComparison . OrdinalIgnoreCase ) >= 0 ;
816
827
}
817
828
829
+ protected async Task HandleCodeActionRequest (
830
+ CodeActionRequest codeActionParams ,
831
+ RequestContext < CodeActionCommand [ ] > requestContext )
832
+ {
833
+ MarkerCorrection correction = null ;
834
+ Dictionary < string , MarkerCorrection > markerIndex = null ;
835
+ List < CodeActionCommand > codeActionCommands = new List < CodeActionCommand > ( ) ;
836
+
837
+ if ( this . codeActionsPerFile . TryGetValue ( codeActionParams . TextDocument . Uri , out markerIndex ) )
838
+ {
839
+ foreach ( var diagnostic in codeActionParams . Context . Diagnostics )
840
+ {
841
+ if ( markerIndex . TryGetValue ( diagnostic . Code , out correction ) )
842
+ {
843
+ codeActionCommands . Add (
844
+ new CodeActionCommand
845
+ {
846
+ Title = correction . Name ,
847
+ Command = "PowerShell.ApplyCodeActionEdits" ,
848
+ Arguments = JArray . FromObject ( correction . Edits )
849
+ } ) ;
850
+ }
851
+ }
852
+ }
853
+
854
+ await requestContext . SendResult (
855
+ codeActionCommands . ToArray ( ) ) ;
856
+ }
857
+
818
858
protected Task HandleEvaluateRequest (
819
859
DebugAdapterMessages . EvaluateRequestArguments evaluateParams ,
820
860
RequestContext < DebugAdapterMessages . EvaluateResponseBody > requestContext )
@@ -974,6 +1014,7 @@ private Task RunScriptDiagnostics(
974
1014
DelayThenInvokeDiagnostics (
975
1015
750 ,
976
1016
filesToAnalyze ,
1017
+ this . codeActionsPerFile ,
977
1018
editorSession ,
978
1019
eventContext ,
979
1020
existingRequestCancellation . Token ) ,
@@ -987,6 +1028,7 @@ private Task RunScriptDiagnostics(
987
1028
private static async Task DelayThenInvokeDiagnostics (
988
1029
int delayMilliseconds ,
989
1030
ScriptFile [ ] filesToAnalyze ,
1031
+ Dictionary < string , Dictionary < string , MarkerCorrection > > correctionIndex ,
990
1032
EditorSession editorSession ,
991
1033
EventContext eventContext ,
992
1034
CancellationToken cancellationToken )
@@ -1034,28 +1076,45 @@ private static async Task DelayThenInvokeDiagnostics(
1034
1076
await PublishScriptDiagnostics (
1035
1077
scriptFile ,
1036
1078
semanticMarkers ,
1079
+ correctionIndex ,
1037
1080
eventContext ) ;
1038
1081
}
1039
1082
}
1040
1083
1041
1084
private static async Task PublishScriptDiagnostics (
1042
1085
ScriptFile scriptFile ,
1043
1086
ScriptFileMarker [ ] semanticMarkers ,
1087
+ Dictionary < string , Dictionary < string , MarkerCorrection > > correctionIndex ,
1044
1088
EventContext eventContext )
1045
1089
{
1046
- var allMarkers = scriptFile . SyntaxMarkers . Concat ( semanticMarkers ) ;
1090
+ List < Diagnostic > diagnostics = new List < Diagnostic > ( ) ;
1091
+
1092
+ // Hold on to any corrections that may need to be applied later
1093
+ Dictionary < string , MarkerCorrection > fileCorrections =
1094
+ new Dictionary < string , MarkerCorrection > ( ) ;
1095
+
1096
+ foreach ( var marker in scriptFile . SyntaxMarkers . Concat ( semanticMarkers ) )
1097
+ {
1098
+ // Does the marker contain a correction?
1099
+ Diagnostic markerDiagnostic = GetDiagnosticFromMarker ( marker ) ;
1100
+ if ( marker . Correction != null )
1101
+ {
1102
+ fileCorrections . Add ( markerDiagnostic . Code , marker . Correction ) ;
1103
+ }
1104
+
1105
+ diagnostics . Add ( markerDiagnostic ) ;
1106
+ }
1107
+
1108
+ correctionIndex [ scriptFile . ClientFilePath ] = fileCorrections ;
1047
1109
1048
- // Always send syntax and semantic errors. We want to
1110
+ // Always send syntax and semantic errors. We want to
1049
1111
// make sure no out-of-date markers are being displayed.
1050
1112
await eventContext . SendEvent (
1051
1113
PublishDiagnosticsNotification . Type ,
1052
1114
new PublishDiagnosticsNotification
1053
1115
{
1054
1116
Uri = scriptFile . ClientFilePath ,
1055
- Diagnostics =
1056
- allMarkers
1057
- . Select ( GetDiagnosticFromMarker )
1058
- . ToArray ( )
1117
+ Diagnostics = diagnostics . ToArray ( )
1059
1118
} ) ;
1060
1119
}
1061
1120
@@ -1065,6 +1124,7 @@ private static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMar
1065
1124
{
1066
1125
Severity = MapDiagnosticSeverity ( scriptFileMarker . Level ) ,
1067
1126
Message = scriptFileMarker . Message ,
1127
+ Code = Guid . NewGuid ( ) . ToString ( ) ,
1068
1128
Range = new Range
1069
1129
{
1070
1130
// TODO: What offsets should I use?
@@ -1145,7 +1205,7 @@ private static CompletionItem CreateCompletionItem(
1145
1205
if ( ! completionDetails . ListItemText . Equals (
1146
1206
completionDetails . ToolTipText ,
1147
1207
StringComparison . OrdinalIgnoreCase ) &&
1148
- ! Regex . IsMatch ( completionDetails . ToolTipText ,
1208
+ ! Regex . IsMatch ( completionDetails . ToolTipText ,
1149
1209
@"^\s*" + escapedToolTipText + @"\s+\[" ) )
1150
1210
{
1151
1211
detailString = completionDetails . ToolTipText ;
@@ -1158,7 +1218,7 @@ private static CompletionItem CreateCompletionItem(
1158
1218
// default (with common params at the end). We just need to make sure the default
1159
1219
// order also be the lexicographical order which we do by prefixig the ListItemText
1160
1220
// with a leading 0's four digit index. This would not sort correctly for a list
1161
- // > 999 parameters but surely we won't have so many items in the "parameter name"
1221
+ // > 999 parameters but surely we won't have so many items in the "parameter name"
1162
1222
// completion list. Technically we don't need the ListItemText at all but it may come
1163
1223
// in handy during debug.
1164
1224
var sortText = ( completionDetails . CompletionType == CompletionType . ParameterName )
0 commit comments