99using Microsoft . PowerShell . EditorServices . Protocol . MessageProtocol . Channel ;
1010using Microsoft . PowerShell . EditorServices . Session ;
1111using Microsoft . PowerShell . EditorServices . Utility ;
12+ using Newtonsoft . Json . Linq ;
1213using System ;
1314using System . Collections . Generic ;
1415using System . IO ;
@@ -31,11 +32,18 @@ public class LanguageServer : LanguageServerBase
3132 private LanguageServerEditorOperations editorOperations ;
3233 private LanguageServerSettings currentSettings = new LanguageServerSettings ( ) ;
3334
35+ < << << << 2d 4012 eee01d844c3e2d46aa538aa348d63530b0
3436 /// <param name="hostDetails">
3537 /// Provides details about the host application.
3638 /// </param>
3739 public LanguageServer ( HostDetails hostDetails , ProfilePaths profilePaths )
3840 : 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
3947 {
4048 }
4149
@@ -92,6 +100,7 @@ protected override void Initialize()
92100 this . SetRequestHandler ( HoverRequest . Type , this . HandleHoverRequest ) ;
93101 this . SetRequestHandler ( DocumentSymbolRequest . Type , this . HandleDocumentSymbolRequest ) ;
94102 this . SetRequestHandler ( WorkspaceSymbolRequest . Type , this . HandleWorkspaceSymbolRequest ) ;
103+ this . SetRequestHandler ( CodeActionRequest . Type , this . HandleCodeActionRequest ) ;
95104
96105 this . SetRequestHandler ( ShowOnlineHelpRequest . Type , this . HandleShowOnlineHelpRequest ) ;
97106 this . SetRequestHandler ( ExpandAliasRequest . Type , this . HandleExpandAliasRequest ) ;
@@ -146,6 +155,7 @@ await requestContext.SendResult(
146155 DocumentSymbolProvider = true ,
147156 WorkspaceSymbolProvider = true ,
148157 HoverProvider = true ,
158+ CodeActionProvider = true ,
149159 CompletionProvider = new CompletionOptions
150160 {
151161 ResolveProvider = true ,
@@ -226,17 +236,17 @@ function __Expand-Alias {
226236 param($targetScript)
227237
228238 [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'}) |
231241 Sort Start -Descending
232242
233243 foreach ($token in $tokens) {
234244 $definition=(Get-Command ('`'+$token.Content) -CommandType Alias -ErrorAction SilentlyContinue).Definition
235245
236- if($definition) {
246+ if($definition) {
237247 $lhs=$targetScript.Substring(0, $token.Start)
238248 $rhs=$targetScript.Substring($token.Start + $token.Length)
239-
249+
240250 $targetScript=$lhs + $definition + $rhs
241251 }
242252 }
@@ -346,13 +356,13 @@ protected async Task HandleDidChangeConfigurationNotification(
346356 EventContext eventContext )
347357 {
348358 bool oldLoadProfiles = this . currentSettings . EnableProfileLoading ;
349- bool oldScriptAnalysisEnabled =
359+ bool oldScriptAnalysisEnabled =
350360 this . currentSettings . ScriptAnalysis . Enable . HasValue ;
351361 string oldScriptAnalysisSettingsPath =
352362 this . currentSettings . ScriptAnalysis . SettingsPath ;
353363
354364 this . currentSettings . Update (
355- configChangeParams . Settings . Powershell ,
365+ configChangeParams . Settings . Powershell ,
356366 this . editorSession . Workspace . WorkspacePath ) ;
357367
358368 if ( ! this . profilesLoaded &&
@@ -386,6 +396,7 @@ protected async Task HandleDidChangeConfigurationNotification(
386396 await PublishScriptDiagnostics (
387397 scriptFile ,
388398 emptyAnalysisDiagnostics ,
399+ this . codeActionsPerFile ,
389400 eventContext ) ;
390401 }
391402 }
@@ -815,6 +826,35 @@ private bool IsQueryMatch(string query, string symbolName)
815826 return symbolName . IndexOf ( query , StringComparison . OrdinalIgnoreCase ) >= 0 ;
816827 }
817828
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+
818858 protected Task HandleEvaluateRequest (
819859 DebugAdapterMessages . EvaluateRequestArguments evaluateParams ,
820860 RequestContext < DebugAdapterMessages . EvaluateResponseBody > requestContext )
@@ -974,6 +1014,7 @@ private Task RunScriptDiagnostics(
9741014 DelayThenInvokeDiagnostics (
9751015 750 ,
9761016 filesToAnalyze ,
1017+ this . codeActionsPerFile ,
9771018 editorSession ,
9781019 eventContext ,
9791020 existingRequestCancellation . Token ) ,
@@ -987,6 +1028,7 @@ private Task RunScriptDiagnostics(
9871028 private static async Task DelayThenInvokeDiagnostics (
9881029 int delayMilliseconds ,
9891030 ScriptFile [ ] filesToAnalyze ,
1031+ Dictionary < string , Dictionary < string , MarkerCorrection > > correctionIndex ,
9901032 EditorSession editorSession ,
9911033 EventContext eventContext ,
9921034 CancellationToken cancellationToken )
@@ -1034,28 +1076,45 @@ private static async Task DelayThenInvokeDiagnostics(
10341076 await PublishScriptDiagnostics (
10351077 scriptFile ,
10361078 semanticMarkers ,
1079+ correctionIndex ,
10371080 eventContext ) ;
10381081 }
10391082 }
10401083
10411084 private static async Task PublishScriptDiagnostics (
10421085 ScriptFile scriptFile ,
10431086 ScriptFileMarker [ ] semanticMarkers ,
1087+ Dictionary < string , Dictionary < string , MarkerCorrection > > correctionIndex ,
10441088 EventContext eventContext )
10451089 {
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 ;
10471109
1048- // Always send syntax and semantic errors. We want to
1110+ // Always send syntax and semantic errors. We want to
10491111 // make sure no out-of-date markers are being displayed.
10501112 await eventContext . SendEvent (
10511113 PublishDiagnosticsNotification . Type ,
10521114 new PublishDiagnosticsNotification
10531115 {
10541116 Uri = scriptFile . ClientFilePath ,
1055- Diagnostics =
1056- allMarkers
1057- . Select ( GetDiagnosticFromMarker )
1058- . ToArray ( )
1117+ Diagnostics = diagnostics . ToArray ( )
10591118 } ) ;
10601119 }
10611120
@@ -1065,6 +1124,7 @@ private static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMar
10651124 {
10661125 Severity = MapDiagnosticSeverity ( scriptFileMarker . Level ) ,
10671126 Message = scriptFileMarker . Message ,
1127+ Code = Guid . NewGuid ( ) . ToString ( ) ,
10681128 Range = new Range
10691129 {
10701130 // TODO: What offsets should I use?
@@ -1145,7 +1205,7 @@ private static CompletionItem CreateCompletionItem(
11451205 if ( ! completionDetails . ListItemText . Equals (
11461206 completionDetails . ToolTipText ,
11471207 StringComparison . OrdinalIgnoreCase ) &&
1148- ! Regex . IsMatch ( completionDetails . ToolTipText ,
1208+ ! Regex . IsMatch ( completionDetails . ToolTipText ,
11491209 @"^\s*" + escapedToolTipText + @"\s+\[" ) )
11501210 {
11511211 detailString = completionDetails . ToolTipText ;
@@ -1158,7 +1218,7 @@ private static CompletionItem CreateCompletionItem(
11581218 // default (with common params at the end). We just need to make sure the default
11591219 // order also be the lexicographical order which we do by prefixig the ListItemText
11601220 // 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"
11621222 // completion list. Technically we don't need the ListItemText at all but it may come
11631223 // in handy during debug.
11641224 var sortText = ( completionDetails . CompletionType == CompletionType . ParameterName )
0 commit comments