From ba3921f85d01183cf2be578f8e523a250a17e3be Mon Sep 17 00:00:00 2001 From: Kapil Borle Date: Fri, 12 May 2017 18:29:37 -0700 Subject: [PATCH 1/8] Add type to request comment help --- .../LanguageServer/CommentHelpRequest.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/PowerShellEditorServices.Protocol/LanguageServer/CommentHelpRequest.cs diff --git a/src/PowerShellEditorServices.Protocol/LanguageServer/CommentHelpRequest.cs b/src/PowerShellEditorServices.Protocol/LanguageServer/CommentHelpRequest.cs new file mode 100644 index 000000000..323efcb1a --- /dev/null +++ b/src/PowerShellEditorServices.Protocol/LanguageServer/CommentHelpRequest.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol; + +namespace Microsoft.PowerShell.EditorServices.Protocol.LanguageServer +{ + class CommentHelpRequest + { + public static readonly RequestType Type + = RequestType.Create("powershell/getCommentHelp"); + } + + public class CommentHelpRequestResult + { + public string[] content; + } + + public class CommentHelpRequestParams + { + public string DocumentUri { get; set; } + public Position TriggerPosition { get; set; } + } +} + From 2691824d9cd82444d92e8e3a932478bbbe5833a0 Mon Sep 17 00:00:00 2001 From: Kapil Borle Date: Fri, 12 May 2017 21:15:39 -0700 Subject: [PATCH 2/8] Handle comment help completion request --- .../LanguageServer/CommentHelpRequest.cs | 4 +- .../Server/LanguageServer.cs | 68 ++++++++++++++++--- .../Language/LanguageService.cs | 21 ++++-- 3 files changed, 76 insertions(+), 17 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/LanguageServer/CommentHelpRequest.cs b/src/PowerShellEditorServices.Protocol/LanguageServer/CommentHelpRequest.cs index 323efcb1a..c01f0f226 100644 --- a/src/PowerShellEditorServices.Protocol/LanguageServer/CommentHelpRequest.cs +++ b/src/PowerShellEditorServices.Protocol/LanguageServer/CommentHelpRequest.cs @@ -10,12 +10,12 @@ namespace Microsoft.PowerShell.EditorServices.Protocol.LanguageServer class CommentHelpRequest { public static readonly RequestType Type - = RequestType.Create("powershell/getCommentHelp"); + = RequestType.Create("powerShell/getCommentHelp"); } public class CommentHelpRequestResult { - public string[] content; + public string[] Content { get; set; } } public class CommentHelpRequestParams diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index b22c11504..2fa395f08 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -20,6 +20,7 @@ using System.Threading; using System.Threading.Tasks; using DebugAdapterMessages = Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter; +using System.Collections; namespace Microsoft.PowerShell.EditorServices.Protocol.Server { @@ -147,7 +148,7 @@ protected override void Initialize() this.SetRequestHandler(ScriptRegionRequest.Type, this.HandleGetFormatScriptRegionRequest); this.SetRequestHandler(GetPSHostProcessesRequest.Type, this.HandleGetPSHostProcessesRequest); - + this.SetRequestHandler(CommentHelpRequest.Type, this.HandleCommentHelpRequest); // Initialize the extension service // TODO: This should be made awaited once Initialize is async! this.editorSession.ExtensionService.Initialize( @@ -241,9 +242,9 @@ private async Task HandleSetPSSARulesRequest( var ruleInfos = dynParams.ruleInfos; foreach (dynamic ruleInfo in ruleInfos) { - if ((Boolean) ruleInfo.isEnabled) + if ((Boolean)ruleInfo.isEnabled) { - activeRules.Add((string) ruleInfo.name); + activeRules.Add((string)ruleInfo.name); } } editorSession.AnalysisService.ActiveRules = activeRules.ToArray(); @@ -307,7 +308,8 @@ private async Task HandleScriptFileMarkersRequest( var markers = await editorSession.AnalysisService.GetSemanticMarkersAsync( editorSession.Workspace.GetFile(requestParams.fileUri), editorSession.AnalysisService.GetPSSASettingsHashtable(requestParams.settings)); - await requestContext.SendResult(new ScriptFileMarkerRequestResultParams { + await requestContext.SendResult(new ScriptFileMarkerRequestResultParams + { markers = markers }); } @@ -569,7 +571,7 @@ protected async Task HandleDidChangeConfigurationNotification( { bool oldLoadProfiles = this.currentSettings.EnableProfileLoading; bool oldScriptAnalysisEnabled = - this.currentSettings.ScriptAnalysis.Enable.HasValue ? this.currentSettings.ScriptAnalysis.Enable.Value : false ; + this.currentSettings.ScriptAnalysis.Enable.HasValue ? this.currentSettings.ScriptAnalysis.Enable.Value : false; string oldScriptAnalysisSettingsPath = this.currentSettings.ScriptAnalysis.SettingsPath; @@ -1072,6 +1074,50 @@ protected async Task HandleGetPSHostProcessesRequest( await requestContext.SendResult(psHostProcesses.ToArray()); } + protected async Task HandleCommentHelpRequest( + CommentHelpRequestParams requestParams, + RequestContext requestContext) + { + var scriptFile = EditorSession.Workspace.GetFile(requestParams.DocumentUri); + var expectedFunctionLine = requestParams.TriggerPosition.Line + 2; + var functionDefinitionAst = EditorSession.LanguageService.GetFunctionDefinitionAtLine( + scriptFile, + expectedFunctionLine); + var result = new CommentHelpRequestResult() + { + Content = new string[] { "" } + }; + + if (functionDefinitionAst != null) + { + var settings = new Dictionary(); + var ruleSettings = new Hashtable(); + ruleSettings.Add("ExportedOnly", false); + ruleSettings.Add("Enable", true); + settings.Add("PSProvideCommentHelp", ruleSettings); + var pssaSettings = EditorSession.AnalysisService.GetPSSASettingsHashtable(settings); + + // todo create a semantic marker api that take only string + var analysisResults = await EditorSession.AnalysisService.GetSemanticMarkersAsync( + scriptFile, + pssaSettings); + + var analysisResult = analysisResults?.FirstOrDefault(x => + { + return x.Correction != null + && x.Correction.Edits[0].StartLineNumber == expectedFunctionLine; + }); + + if (analysisResult != null) + { + // find the analysis result whose correction starts on + result.Content = analysisResult.Correction.Edits[0].Text.Split('\n').Select(x => x.Trim('\r')).ToArray(); + } + } + + await requestContext.SendResult(result); + } + private bool IsQueryMatch(string query, string symbolName) { return symbolName.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0; @@ -1134,12 +1180,12 @@ protected Task HandleEvaluateRequest( // Return an empty result since the result value is irrelevant // for this request in the LanguageServer return - requestContext.SendResult( - new DebugAdapterMessages.EvaluateResponseBody - { - Result = "", - VariablesReference = 0 - }); + requestContext.SendResult( + new DebugAdapterMessages.EvaluateResponseBody + { + Result = "", + VariablesReference = 0 + }); }); return Task.FromResult(true); diff --git a/src/PowerShellEditorServices/Language/LanguageService.cs b/src/PowerShellEditorServices/Language/LanguageService.cs index 511110e5c..1cfb0ae9a 100644 --- a/src/PowerShellEditorServices/Language/LanguageService.cs +++ b/src/PowerShellEditorServices/Language/LanguageService.cs @@ -115,7 +115,7 @@ await AstOperations.GetCompletions( return completionResults; } - catch(ArgumentException e) + catch (ArgumentException e) { // Bad completion results could return an invalid // replacement range, catch that here @@ -231,7 +231,8 @@ public FindOccurrencesResult FindSymbolsInFile(ScriptFile scriptFile) AstOperations .FindSymbolsInDocument(scriptFile.ScriptAst, this.powerShellContext.LocalPowerShellVersion.Version) .Select( - reference => { + reference => + { reference.SourceLine = scriptFile.GetLine(reference.ScriptRegion.StartLineNumber); reference.FilePath = scriptFile.FilePath; @@ -239,7 +240,8 @@ public FindOccurrencesResult FindSymbolsInFile(ScriptFile scriptFile) }); return - new FindOccurrencesResult { + new FindOccurrencesResult + { FoundOccurrences = symbolReferencesinFile }; } @@ -267,7 +269,7 @@ public async Task FindReferencesOfSymbol( // We want to look for references first in referenced files, hence we use ordered dictionary var fileMap = new OrderedDictionary(StringComparer.OrdinalIgnoreCase); - foreach(ScriptFile file in referencedFiles) + foreach (ScriptFile file in referencedFiles) { fileMap.Add(file.FilePath, file); } @@ -520,6 +522,17 @@ public ScriptRegion FindSmallestStatementAstRegion( return ScriptRegion.Create(ast.Extent); } + public FunctionDefinitionAst GetFunctionDefinitionAtLine( + ScriptFile scriptFile, + int lineNumber) + { + var functionDefinitionAst = scriptFile.ScriptAst.Find( + ast => ast is FunctionDefinitionAst && ast.Extent.StartLineNumber == lineNumber, + true); + + return functionDefinitionAst as FunctionDefinitionAst; + } + #endregion #region Private Fields From f7719fde77cfe1cebbde5fd0cc5228a2cc8695d8 Mon Sep 17 00:00:00 2001 From: Kapil Borle Date: Sun, 14 May 2017 10:58:40 -0700 Subject: [PATCH 3/8] Add option for comment style in comment help --- .../LanguageServer/CommentHelpRequest.cs | 1 + src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/PowerShellEditorServices.Protocol/LanguageServer/CommentHelpRequest.cs b/src/PowerShellEditorServices.Protocol/LanguageServer/CommentHelpRequest.cs index c01f0f226..d4406519f 100644 --- a/src/PowerShellEditorServices.Protocol/LanguageServer/CommentHelpRequest.cs +++ b/src/PowerShellEditorServices.Protocol/LanguageServer/CommentHelpRequest.cs @@ -22,6 +22,7 @@ public class CommentHelpRequestParams { public string DocumentUri { get; set; } public Position TriggerPosition { get; set; } + public bool BlockComment { get; set; } } } diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 2fa395f08..4c4843d8c 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -1094,6 +1094,7 @@ protected async Task HandleCommentHelpRequest( var ruleSettings = new Hashtable(); ruleSettings.Add("ExportedOnly", false); ruleSettings.Add("Enable", true); + ruleSettings.Add("BlockComment", requestParams.BlockComment); settings.Add("PSProvideCommentHelp", ruleSettings); var pssaSettings = EditorSession.AnalysisService.GetPSSASettingsHashtable(settings); From f0419d6c08bacebe25a8a29f536e921ce0ce0a23 Mon Sep 17 00:00:00 2001 From: Kapil Borle Date: Tue, 16 May 2017 20:38:02 -0700 Subject: [PATCH 4/8] Return a vscode snippet instead of string --- src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 4c4843d8c..6a2dd29d9 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -1095,6 +1095,7 @@ protected async Task HandleCommentHelpRequest( ruleSettings.Add("ExportedOnly", false); ruleSettings.Add("Enable", true); ruleSettings.Add("BlockComment", requestParams.BlockComment); + ruleSettings.Add("VSCodeSnippetCorrection", true); settings.Add("PSProvideCommentHelp", ruleSettings); var pssaSettings = EditorSession.AnalysisService.GetPSSASettingsHashtable(settings); From c42f05b7bfa0710704574f21120759b083778179 Mon Sep 17 00:00:00 2001 From: Kapil Borle Date: Tue, 16 May 2017 21:03:06 -0700 Subject: [PATCH 5/8] Fix comment help completion when function not in context --- .../Server/LanguageServer.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 6a2dd29d9..b2e97d686 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -1083,10 +1083,7 @@ protected async Task HandleCommentHelpRequest( var functionDefinitionAst = EditorSession.LanguageService.GetFunctionDefinitionAtLine( scriptFile, expectedFunctionLine); - var result = new CommentHelpRequestResult() - { - Content = new string[] { "" } - }; + var result = new CommentHelpRequestResult(); if (functionDefinitionAst != null) { @@ -1096,6 +1093,7 @@ protected async Task HandleCommentHelpRequest( ruleSettings.Add("Enable", true); ruleSettings.Add("BlockComment", requestParams.BlockComment); ruleSettings.Add("VSCodeSnippetCorrection", true); + ruleSettings.Add("Placement", "before"); settings.Add("PSProvideCommentHelp", ruleSettings); var pssaSettings = EditorSession.AnalysisService.GetPSSASettingsHashtable(settings); @@ -1110,11 +1108,8 @@ protected async Task HandleCommentHelpRequest( && x.Correction.Edits[0].StartLineNumber == expectedFunctionLine; }); - if (analysisResult != null) - { - // find the analysis result whose correction starts on - result.Content = analysisResult.Correction.Edits[0].Text.Split('\n').Select(x => x.Trim('\r')).ToArray(); - } + // find the analysis result whose correction starts on + result.Content = analysisResult?.Correction.Edits[0].Text.Split('\n').Select(x => x.Trim('\r')).ToArray(); } await requestContext.SendResult(result); From 3479f66124a80c5c7030aa5e5dd81b671445698f Mon Sep 17 00:00:00 2001 From: Kapil Borle Date: Wed, 17 May 2017 18:20:35 -0700 Subject: [PATCH 6/8] Make AnalysisService.GetPSSASettingsHashtable static --- .../Server/LanguageServer.cs | 4 ++-- src/PowerShellEditorServices/Analysis/AnalysisService.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index b2e97d686..65f60c78a 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -307,7 +307,7 @@ private async Task HandleScriptFileMarkersRequest( { var markers = await editorSession.AnalysisService.GetSemanticMarkersAsync( editorSession.Workspace.GetFile(requestParams.fileUri), - editorSession.AnalysisService.GetPSSASettingsHashtable(requestParams.settings)); + AnalysisService.GetPSSASettingsHashtable(requestParams.settings)); await requestContext.SendResult(new ScriptFileMarkerRequestResultParams { markers = markers @@ -1095,7 +1095,7 @@ protected async Task HandleCommentHelpRequest( ruleSettings.Add("VSCodeSnippetCorrection", true); ruleSettings.Add("Placement", "before"); settings.Add("PSProvideCommentHelp", ruleSettings); - var pssaSettings = EditorSession.AnalysisService.GetPSSASettingsHashtable(settings); + var pssaSettings = AnalysisService.GetPSSASettingsHashtable(settings); // todo create a semantic marker api that take only string var analysisResults = await EditorSession.AnalysisService.GetSemanticMarkersAsync( diff --git a/src/PowerShellEditorServices/Analysis/AnalysisService.cs b/src/PowerShellEditorServices/Analysis/AnalysisService.cs index 5aa9e1a9f..f7df00ca9 100644 --- a/src/PowerShellEditorServices/Analysis/AnalysisService.cs +++ b/src/PowerShellEditorServices/Analysis/AnalysisService.cs @@ -186,7 +186,7 @@ public IEnumerable GetPSScriptAnalyzerRules() /// /// A settings hashtable /// - public Hashtable GetPSSASettingsHashtable(IDictionary ruleSettingsMap) + public static Hashtable GetPSSASettingsHashtable(IDictionary ruleSettingsMap) { var hashtable = new Hashtable(); var ruleSettingsHashtable = new Hashtable(); From e65e08d03c68b760ac7cde572d664ea6140b69cf Mon Sep 17 00:00:00 2001 From: Kapil Borle Date: Wed, 17 May 2017 18:21:03 -0700 Subject: [PATCH 7/8] Fix PSUseDeclaredVarsMoreThanAssignments rule name --- src/PowerShellEditorServices/Analysis/AnalysisService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices/Analysis/AnalysisService.cs b/src/PowerShellEditorServices/Analysis/AnalysisService.cs index f7df00ca9..33991bb69 100644 --- a/src/PowerShellEditorServices/Analysis/AnalysisService.cs +++ b/src/PowerShellEditorServices/Analysis/AnalysisService.cs @@ -55,7 +55,7 @@ private bool hasScriptAnalyzerModule "PSShouldProcess", "PSMissingModuleManifestField", "PSAvoidDefaultValueSwitchParameter", - "PSUseDeclaredVarsMoreThanAssigments" + "PSUseDeclaredVarsMoreThanAssignments" }; #endregion // Private Fields From 6884781b1bb1c6c55ae705c2b2a7bd4a719f3949 Mon Sep 17 00:00:00 2001 From: Kapil Borle Date: Wed, 17 May 2017 18:41:04 -0700 Subject: [PATCH 8/8] Move rule settings related code to AnalysisService --- .../Server/LanguageServer.cs | 19 ++--- .../Analysis/AnalysisService.cs | 69 +++++++++++++------ .../Language/LanguageService.cs | 6 ++ 3 files changed, 61 insertions(+), 33 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 65f60c78a..c2978e18e 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -1087,20 +1087,15 @@ protected async Task HandleCommentHelpRequest( if (functionDefinitionAst != null) { - var settings = new Dictionary(); - var ruleSettings = new Hashtable(); - ruleSettings.Add("ExportedOnly", false); - ruleSettings.Add("Enable", true); - ruleSettings.Add("BlockComment", requestParams.BlockComment); - ruleSettings.Add("VSCodeSnippetCorrection", true); - ruleSettings.Add("Placement", "before"); - settings.Add("PSProvideCommentHelp", ruleSettings); - var pssaSettings = AnalysisService.GetPSSASettingsHashtable(settings); - - // todo create a semantic marker api that take only string + // todo create a semantic marker api that take only string var analysisResults = await EditorSession.AnalysisService.GetSemanticMarkersAsync( scriptFile, - pssaSettings); + AnalysisService.GetCommentHelpRuleSettings( + true, + false, + requestParams.BlockComment, + true, + "before")); var analysisResult = analysisResults?.FirstOrDefault(x => { diff --git a/src/PowerShellEditorServices/Analysis/AnalysisService.cs b/src/PowerShellEditorServices/Analysis/AnalysisService.cs index 33991bb69..f5987d888 100644 --- a/src/PowerShellEditorServices/Analysis/AnalysisService.cs +++ b/src/PowerShellEditorServices/Analysis/AnalysisService.cs @@ -141,6 +141,54 @@ public AnalysisService(IConsoleHost consoleHost, string settingsPath = null) #region Public Methods + /// + /// Get PSScriptAnalyzer settings hashtable for PSProvideCommentHelp rule. + /// + /// Enable the rule. + /// Analyze only exported functions/cmdlets. + /// Use block comment or line comment. + /// Return a vscode snipped correction should be returned. + /// Place comment help at the given location relative to the function definition. + /// A PSScriptAnalyzer settings hashtable. + public static Hashtable GetCommentHelpRuleSettings( + bool enable, + bool exportedOnly, + bool blockComment, + bool vscodeSnippetCorrection, + string placement) + { + var settings = new Dictionary(); + var ruleSettings = new Hashtable(); + ruleSettings.Add("Enable", enable); + ruleSettings.Add("ExportedOnly", exportedOnly); + ruleSettings.Add("BlockComment", blockComment); + ruleSettings.Add("VSCodeSnippetCorrection", vscodeSnippetCorrection); + ruleSettings.Add("Placement", placement); + settings.Add("PSProvideCommentHelp", ruleSettings); + return GetPSSASettingsHashtable(settings); + } + + /// + /// Construct a PSScriptAnalyzer settings hashtable + /// + /// A settings hashtable + /// + public static Hashtable GetPSSASettingsHashtable(IDictionary ruleSettingsMap) + { + var hashtable = new Hashtable(); + var ruleSettingsHashtable = new Hashtable(); + + hashtable["IncludeRules"] = ruleSettingsMap.Keys.ToArray(); + hashtable["Rules"] = ruleSettingsHashtable; + + foreach (var kvp in ruleSettingsMap) + { + ruleSettingsHashtable.Add(kvp.Key, kvp.Value); + } + + return hashtable; + } + /// /// Perform semantic analysis on the given ScriptFile and returns /// an array of ScriptFileMarkers. @@ -181,27 +229,6 @@ public IEnumerable GetPSScriptAnalyzerRules() return ruleNames; } - /// - /// Construct a PSScriptAnalyzer settings hashtable - /// - /// A settings hashtable - /// - public static Hashtable GetPSSASettingsHashtable(IDictionary ruleSettingsMap) - { - var hashtable = new Hashtable(); - var ruleSettingsHashtable = new Hashtable(); - - hashtable["IncludeRules"] = ruleSettingsMap.Keys.ToArray(); - hashtable["Rules"] = ruleSettingsHashtable; - - foreach (var kvp in ruleSettingsMap) - { - ruleSettingsHashtable.Add(kvp.Key, kvp.Value); - } - - return hashtable; - } - /// /// Disposes the runspace being used by the analysis service. /// diff --git a/src/PowerShellEditorServices/Language/LanguageService.cs b/src/PowerShellEditorServices/Language/LanguageService.cs index 1cfb0ae9a..3a953f5f5 100644 --- a/src/PowerShellEditorServices/Language/LanguageService.cs +++ b/src/PowerShellEditorServices/Language/LanguageService.cs @@ -522,6 +522,12 @@ public ScriptRegion FindSmallestStatementAstRegion( return ScriptRegion.Create(ast.Extent); } + /// + /// Gets the function defined on a given line. + /// + /// Open script file. + /// The 1 based line on which to look for function definition. + /// If found, returns the function definition on the given line. Otherwise, returns null. public FunctionDefinitionAst GetFunctionDefinitionAtLine( ScriptFile scriptFile, int lineNumber)