Skip to content

Commit 32ef5b9

Browse files
Folding support (PowerShell#20)
* Added Diagnostics * didChangeConfiguration message and general settings support * initial folding support * log level trace * folding works with latest omnisharp version * comment typo * added test for folding
1 parent 8f1bdc6 commit 32ef5b9

File tree

8 files changed

+462
-6
lines changed

8 files changed

+462
-6
lines changed

NuGet.Config

+3
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@
33
<solution>
44
<add key="disableSourceControlIntegration" value="true" />
55
</solution>
6+
<packageSources>
7+
<add key="nuget.org" value="https://www.myget.org/F/omnisharp/api/v3/index.json" protocolVersion="3" />
8+
</packageSources>
69
</configuration>

src/PowerShellEditorServices.Engine/Hosting/EditorServicesHost.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ public void StartLanguageService(
241241
{
242242
NamedPipeName = config.InOutPipeName ?? config.InPipeName,
243243
OutNamedPipeName = config.OutPipeName,
244-
LoggerFactory = _factory
244+
LoggerFactory = _factory,
245+
MinimumLogLevel = LogLevel.Trace,
245246
}
246247
.BuildLanguageServer();
247248

src/PowerShellEditorServices.Engine/LanguageServer/OmnisharpLanguageServer.cs

+6-4
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,12 @@ public async Task StartAsync()
6868
options.LoggerFactory = _configuration.LoggerFactory;
6969
options.MinimumLogLevel = _configuration.MinimumLogLevel;
7070
options.Services = _configuration.Services;
71-
options.WithHandler<WorkspaceSymbolsHandler>();
72-
options.WithHandler<TextDocumentHandler>();
73-
options.WithHandler<GetVersionHandler>();
74-
options.WithHandler<ConfigurationHandler>();
71+
options
72+
.WithHandler<WorkspaceSymbolsHandler>()
73+
.WithHandler<TextDocumentHandler>()
74+
.WithHandler<GetVersionHandler>()
75+
.WithHandler<ConfigurationHandler>()
76+
.WithHandler<FoldingRangeHandler>();
7577
});
7678

7779
_serverStart.SetResult(true);

src/PowerShellEditorServices.Engine/PowerShellEditorServices.Engine.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
<ItemGroup>
1414
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" Version="2.2.0" />
15-
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="0.12.1" />
15+
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="0.13.0-*" />
1616
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" />
1717
<PackageReference Include="Serilog.Extensions.Logging" Version="2.0.4" />
1818
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
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 System;
7+
using System.Collections.Generic;
8+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
9+
10+
namespace Microsoft.PowerShell.EditorServices
11+
{
12+
/// <summary>
13+
/// A class that holds the information for a foldable region of text in a document
14+
/// </summary>
15+
public class FoldingReference: IComparable<FoldingReference>
16+
{
17+
/// <summary>
18+
/// The zero-based line number from where the folded range starts.
19+
/// </summary>
20+
public int StartLine { get; set; }
21+
22+
/// <summary>
23+
/// The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line.
24+
/// </summary>
25+
public int StartCharacter { get; set; } = 0;
26+
27+
/// <summary>
28+
/// The zero-based line number where the folded range ends.
29+
/// </summary>
30+
public int EndLine { get; set; }
31+
32+
/// <summary>
33+
/// The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line.
34+
/// </summary>
35+
public int EndCharacter { get; set; } = 0;
36+
37+
/// <summary>
38+
/// Describes the kind of the folding range such as `comment' or 'region'.
39+
/// </summary>
40+
public FoldingRangeKind? Kind { get; set; }
41+
42+
/// <summary>
43+
/// A custom comparable method which can properly sort FoldingReference objects
44+
/// </summary>
45+
public int CompareTo(FoldingReference that) {
46+
// Initially look at the start line
47+
if (this.StartLine < that.StartLine) { return -1; }
48+
if (this.StartLine > that.StartLine) { return 1; }
49+
50+
// They have the same start line so now consider the end line.
51+
// The biggest line range is sorted first
52+
if (this.EndLine > that.EndLine) { return -1; }
53+
if (this.EndLine < that.EndLine) { return 1; }
54+
55+
// They have the same lines, but what about character offsets
56+
if (this.StartCharacter < that.StartCharacter) { return -1; }
57+
if (this.StartCharacter > that.StartCharacter) { return 1; }
58+
if (this.EndCharacter < that.EndCharacter) { return -1; }
59+
if (this.EndCharacter > that.EndCharacter) { return 1; }
60+
61+
// They're the same range, but what about kind
62+
return that.Kind.Value - this.Kind.Value;
63+
}
64+
}
65+
66+
/// <summary>
67+
/// A class that holds a list of FoldingReferences and ensures that when adding a reference that the
68+
/// folding rules are obeyed, e.g. Only one fold per start line
69+
/// </summary>
70+
public class FoldingReferenceList
71+
{
72+
private readonly Dictionary<int, FoldingReference> references = new Dictionary<int, FoldingReference>();
73+
74+
/// <summary>
75+
/// Return all references in the list
76+
/// </summary>
77+
public IEnumerable<FoldingReference> References
78+
{
79+
get
80+
{
81+
return references.Values;
82+
}
83+
}
84+
85+
/// <summary>
86+
/// Adds a FoldingReference to the list and enforces ordering rules e.g. Only one fold per start line
87+
/// </summary>
88+
public void SafeAdd(FoldingReference item)
89+
{
90+
if (item == null) { return; }
91+
92+
// Only add the item if it hasn't been seen before or it's the largest range
93+
if (references.TryGetValue(item.StartLine, out FoldingReference currentItem))
94+
{
95+
if (currentItem.CompareTo(item) == 1) { references[item.StartLine] = item; }
96+
}
97+
else
98+
{
99+
references[item.StartLine] = item;
100+
}
101+
}
102+
103+
/// <summary>
104+
/// Helper method to easily convert the Dictionary Values into an array
105+
/// </summary>
106+
public FoldingReference[] ToArray()
107+
{
108+
var result = new FoldingReference[references.Count];
109+
references.Values.CopyTo(result, 0);
110+
return result;
111+
}
112+
}
113+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System.Collections.Generic;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using Microsoft.Extensions.Logging;
5+
using Microsoft.PowerShell.EditorServices;
6+
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
7+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
8+
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
9+
10+
namespace PowerShellEditorServices.Engine.Services.Handlers
11+
{
12+
public class FoldingRangeHandler : IFoldingRangeHandler
13+
{
14+
private readonly DocumentSelector _documentSelector = new DocumentSelector(
15+
new DocumentFilter()
16+
{
17+
Pattern = "**/*.ps*1"
18+
}
19+
);
20+
21+
private readonly ILogger _logger;
22+
private readonly ConfigurationService _configurationService;
23+
private readonly WorkspaceService _workspaceService;
24+
25+
private FoldingRangeCapability _capability;
26+
27+
public FoldingRangeHandler(ILoggerFactory factory, ConfigurationService configurationService, WorkspaceService workspaceService)
28+
{
29+
_logger = factory.CreateLogger<FoldingRangeHandler>();
30+
_configurationService = configurationService;
31+
_workspaceService = workspaceService;
32+
}
33+
public TextDocumentRegistrationOptions GetRegistrationOptions()
34+
{
35+
return new TextDocumentRegistrationOptions()
36+
{
37+
DocumentSelector = _documentSelector,
38+
};
39+
}
40+
41+
public Task<Container<FoldingRange>> Handle(FoldingRangeRequestParam request, CancellationToken cancellationToken)
42+
{
43+
// TODO Should be using dynamic registrations
44+
if (!_configurationService.CurrentSettings.CodeFolding.Enable) { return null; }
45+
46+
// Avoid crash when using untitled: scheme or any other scheme where the document doesn't
47+
// have a backing file. https://github.com/PowerShell/vscode-powershell/issues/1676
48+
// Perhaps a better option would be to parse the contents of the document as a string
49+
// as opposed to reading a file but the scenario of "no backing file" probably doesn't
50+
// warrant the extra effort.
51+
if (!_workspaceService.TryGetFile(request.TextDocument.Uri.ToString(), out ScriptFile scriptFile)) { return null; }
52+
53+
var result = new List<FoldingRange>();
54+
55+
// If we're showing the last line, decrement the Endline of all regions by one.
56+
int endLineOffset = _configurationService.CurrentSettings.CodeFolding.ShowLastLine ? -1 : 0;
57+
58+
foreach (FoldingReference fold in TokenOperations.FoldableReferences(scriptFile.ScriptTokens).References)
59+
{
60+
result.Add(new FoldingRange {
61+
EndCharacter = fold.EndCharacter,
62+
EndLine = fold.EndLine + endLineOffset,
63+
Kind = fold.Kind,
64+
StartCharacter = fold.StartCharacter,
65+
StartLine = fold.StartLine
66+
});
67+
}
68+
69+
return Task.FromResult(new Container<FoldingRange>(result));
70+
}
71+
72+
public void SetCapability(FoldingRangeCapability capability)
73+
{
74+
_capability = capability;
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)