From 61014e19d1b4b8f0096ab6271fe6902e61a53a3b Mon Sep 17 00:00:00 2001 From: Glenn Sarti Date: Mon, 12 Nov 2018 20:01:26 +0800 Subject: [PATCH] (GH-793) Add support for Folding Range client settings This commit uses the the client configuration settings to modify the behaviour of the server. In particular the Enable and ShowLastLine setting. * The enable setting will change the provider to return null when disabled * The ShowLastLine setting emulates the behaviour in https://github.com/PowerShell/vscode-powershell/pull/1557 * Modifies conversion method for the internal region class to FoldingRange object to show/hide the last line based on the extension settings * Modifies the tests for the default value and adds tests for the show and hide scenarios --- .../Server/LanguageServer.cs | 5 +- .../Server/LanguageServerSettings.cs | 46 ++++++++++++++++ .../Language/TokenOperations.cs | 11 +++- .../Language/TokenOperationsTests.cs | 53 ++++++++++++------- 4 files changed, 93 insertions(+), 22 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 44f19952f2..78a5968cb9 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -1301,10 +1301,13 @@ protected Task HandleEvaluateRequest( private FoldingRange[] Fold( string documentUri) { + // TODO Should I be using dynamic registrations? + if (this.currentSettings.CodeFolding.Enable != true) { return null; } // TODO Surely there's a better way to do type adapters? List result = new List(); foreach (FoldingReference fold in TokenOperations.FoldableRegions( - editorSession.Workspace.GetFile(documentUri).ScriptTokens)) + editorSession.Workspace.GetFile(documentUri).ScriptTokens, + this.currentSettings.CodeFolding.ShowLastLine)) { FoldingRange item = new FoldingRange(); item.EndCharacter = fold.EndCharacter; diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServerSettings.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServerSettings.cs index 05b3e6e065..6ea3ca9fba 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServerSettings.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServerSettings.cs @@ -20,10 +20,13 @@ public class LanguageServerSettings public CodeFormattingSettings CodeFormatting { get; set; } + public CodeFoldingSettings CodeFolding { get; set; } + public LanguageServerSettings() { this.ScriptAnalysis = new ScriptAnalysisSettings(); this.CodeFormatting = new CodeFormattingSettings(); + this.CodeFolding = new CodeFoldingSettings(); } public void Update( @@ -39,6 +42,7 @@ public void Update( workspaceRootPath, logger); this.CodeFormatting = new CodeFormattingSettings(settings.CodeFormatting); + this.CodeFolding.Update(settings.CodeFolding, logger); } } } @@ -261,6 +265,48 @@ private Hashtable GetCustomPSSASettingsHashtable(int tabSize, bool insertSpaces) } } + /// + /// Code folding settings + /// + public class CodeFoldingSettings + { + /// + /// Whether the folding is enabled. Default is true as per VSCode + /// + public bool Enable { get; set; } = true; + + /// + /// Whether to show or hide the last line of a folding region. Default is true as per VSCode + /// + public bool ShowLastLine { get; set; } = true; + + /// + /// Settings constructor; including the default settings. + /// + public CodeFoldingSettings() + { + } + + /// + /// Update these settings from another settings object + /// + public void Update( + CodeFoldingSettings settings, + ILogger logger) + { + if (settings != null) { + if (settings.Enable != null) { + this.Enable = settings.Enable; + logger.Write(LogLevel.Verbose, string.Format("Using Code Folding Enabled - {0}", this.Enable)); + } + if (settings.ShowLastLine != null) { + this.ShowLastLine = settings.ShowLastLine; + logger.Write(LogLevel.Verbose, string.Format("Using Code Folding ShowLastLine - {0}", this.ShowLastLine)); + } + } + } + } + public class LanguageServerSettingsWrapper { // NOTE: This property is capitalized as 'Powershell' because the diff --git a/src/PowerShellEditorServices/Language/TokenOperations.cs b/src/PowerShellEditorServices/Language/TokenOperations.cs index bddada76ed..f34738ee97 100644 --- a/src/PowerShellEditorServices/Language/TokenOperations.cs +++ b/src/PowerShellEditorServices/Language/TokenOperations.cs @@ -18,7 +18,10 @@ internal static class TokenOperations /// /// Extracts all of the unique foldable regions in a script given the list tokens /// - static public FoldingReference[] FoldableRegions(Token[] tokens) { + static public FoldingReference[] FoldableRegions( + Token[] tokens, + bool ShowLastLine) + { List foldableRegions = new List(); // Find matching braces { -> } @@ -89,6 +92,12 @@ static public FoldingReference[] FoldableRegions(Token[] tokens) { return (item.StartLine == foldableRegions[index - 1].StartLine); }); + // Some editors have different folding UI, sometimes the lastline should be displayed + // If we do want to show the last line, just change the region to be one line less + if (ShowLastLine) { + foldableRegions.ForEach( item => { item.EndLine--; }); + } + return foldableRegions.ToArray(); } diff --git a/test/PowerShellEditorServices.Test/Language/TokenOperationsTests.cs b/test/PowerShellEditorServices.Test/Language/TokenOperationsTests.cs index 2349bb77a8..f1a568c224 100644 --- a/test/PowerShellEditorServices.Test/Language/TokenOperationsTests.cs +++ b/test/PowerShellEditorServices.Test/Language/TokenOperationsTests.cs @@ -13,13 +13,13 @@ public class TokenOperationsTests /// /// Helper methiod to create a stub script file and then call FoldableRegions /// - private FoldingReference[] GetRegions(string text) { + private FoldingReference[] GetRegions(string text, bool showLastLine = true) { ScriptFile scriptFile = new ScriptFile( "testfile", "clienttestfile", text, Version.Parse("5.0")); - return Microsoft.PowerShell.EditorServices.TokenOperations.FoldableRegions(scriptFile.ScriptTokens); + return Microsoft.PowerShell.EditorServices.TokenOperations.FoldableRegions(scriptFile.ScriptTokens, showLastLine); } // This PowerShell script will exercise all of the @@ -100,21 +100,21 @@ double quoted herestrings should also fold $something = $true #endregion Comment Block 3"; private FoldingReference[] expectedAllInOneScriptFolds = { - new FoldingReference(0, 0, 4, 10, "region"), - new FoldingReference(1, 0, 3, 2, "comment"), - new FoldingReference(10, 0, 15, 2, "comment"), - new FoldingReference(16, 30, 60, 1, null), - new FoldingReference(17, 0, 22, 2, "comment"), - new FoldingReference(23, 7, 26, 2, null), - new FoldingReference(28, 5, 31, 2, null), - new FoldingReference(35, 2, 37, 0, "comment"), - new FoldingReference(39, 2, 49, 14, "region"), - new FoldingReference(41, 4, 45, 14, "region"), - new FoldingReference(51, 7, 53, 3, null), - new FoldingReference(56, 7, 59, 3, null), - new FoldingReference(64, 0, 66, 0, "comment"), - new FoldingReference(67, 0, 72, 26, "region"), - new FoldingReference(68, 0, 70, 0, "comment") + new FoldingReference(0, 0, 3, 10, "region"), + new FoldingReference(1, 0, 2, 2, "comment"), + new FoldingReference(10, 0, 14, 2, "comment"), + new FoldingReference(16, 30, 59, 1, null), + new FoldingReference(17, 0, 21, 2, "comment"), + new FoldingReference(23, 7, 25, 2, null), + new FoldingReference(28, 5, 30, 2, null), + new FoldingReference(35, 2, 36, 0, "comment"), + new FoldingReference(39, 2, 48, 14, "region"), + new FoldingReference(41, 4, 44, 14, "region"), + new FoldingReference(51, 7, 52, 3, null), + new FoldingReference(56, 7, 58, 3, null), + new FoldingReference(64, 0, 65, 0, "comment"), + new FoldingReference(67, 0, 71, 26, "region"), + new FoldingReference(68, 0, 69, 0, "comment") }; /// @@ -155,6 +155,19 @@ public void LaguageServiceFindsFoldablRegionsWithCRLF() { AssertFoldingReferenceArrays(expectedAllInOneScriptFolds, result); } + [Fact] + public void LaguageServiceFindsFoldablRegionsWithoutLastLine() { + FoldingReference[] result = GetRegions(allInOneScript, false); + // Incrememnt the end line of the expected regions by one as we will + // be hiding the last line + FoldingReference[] expectedFolds = expectedAllInOneScriptFolds.Clone() as FoldingReference[]; + for (int index = 0; index < expectedFolds.Length; index++) + { + expectedFolds[index].EndLine++; + } + AssertFoldingReferenceArrays(expectedFolds, result); + } + [Fact] public void LaguageServiceFindsFoldablRegionsWithMismatchedRegions() { string testString = @@ -167,7 +180,7 @@ public void LaguageServiceFindsFoldablRegionsWithMismatchedRegions() { #region should not fold - mismatched "; FoldingReference[] expectedFolds = { - new FoldingReference(2, 0, 4, 10, "region") + new FoldingReference(2, 0, 3, 10, "region") }; FoldingReference[] result = GetRegions(testString); @@ -184,8 +197,8 @@ public void LaguageServiceFindsFoldablRegionsWithDuplicateRegions() { }) "; FoldingReference[] expectedFolds = { - new FoldingReference(1, 64, 2, 27, null), - new FoldingReference(2, 35, 4, 2, null) + new FoldingReference(1, 64, 1, 27, null), + new FoldingReference(2, 35, 3, 2, null) }; FoldingReference[] result = GetRegions(testString);