Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 27b5325

Browse files
Add SortDocumentSymbols to make the outline hierarchical (again)
This is probably what OmniSharp was doing for us.
1 parent 7e130e9 commit 27b5325

File tree

1 file changed

+85
-6
lines changed

1 file changed

+85
-6
lines changed

‎src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs‎

Lines changed: 85 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,79 @@ public PsesDocumentSymbolHandler(ILoggerFactory factory, WorkspaceService worksp
4040
DocumentSelector = LspUtils.PowerShellDocumentSelector
4141
};
4242

43+
// This turns a flat list of symbols into a hierarchical list. It's ugly because we're
44+
// dealing with records and so sadly must slowly copy and replace things whenever need to do
45+
// a modification, but it seems to work.
46+
private static async Task<List<DocumentSymbol>> SortDocumentSymbols(List<DocumentSymbol> symbols, CancellationToken cancellationToken)
47+
{
48+
// Sort by the start of the symbol definition.
49+
symbols.Sort((x1, x2) => x1.Range.Start.CompareTo(x2.Range.Start));
50+
51+
List<DocumentSymbol> parents = new();
52+
53+
foreach (DocumentSymbol symbol in symbols)
54+
{
55+
// This async method is pretty dense with synchronous code
56+
// so it's helpful to add some yields.
57+
await Task.Yield();
58+
if (cancellationToken.IsCancellationRequested)
59+
{
60+
return symbols;
61+
}
62+
63+
// Base case.
64+
if (parents.Count == 0)
65+
{
66+
parents.Add(symbol);
67+
}
68+
// Symbol starts after end of last symbol parsed.
69+
else if (symbol.Range.Start > parents[parents.Count - 1].Range.End)
70+
{
71+
parents.Add(symbol);
72+
}
73+
// Find where it fits.
74+
else
75+
{
76+
for (int i = 0; i < parents.Count; i++)
77+
{
78+
DocumentSymbol parent = parents[i];
79+
if (parent.Range.Start <= symbol.Range.Start && symbol.Range.End <= parent.Range.End)
80+
{
81+
List<DocumentSymbol> children = new();
82+
if (parent.Children is not null)
83+
{
84+
children.AddRange(parent.Children);
85+
}
86+
children.Add(symbol);
87+
parents[i] = parent with { Children = children };
88+
break;
89+
}
90+
}
91+
}
92+
}
93+
94+
// Recursively sort the children.
95+
for (int i = 0; i < parents.Count; i++)
96+
{
97+
DocumentSymbol parent = parents[i];
98+
if (parent.Children is not null)
99+
{
100+
List<DocumentSymbol> children = new(parent.Children);
101+
children = await SortDocumentSymbols(children, cancellationToken).ConfigureAwait(false);
102+
parents[i] = parent with { Children = children };
103+
}
104+
}
105+
106+
return parents;
107+
}
108+
43109
// AKA the outline feature
44110
public override async Task<SymbolInformationOrDocumentSymbolContainer> Handle(DocumentSymbolParams request, CancellationToken cancellationToken)
45111
{
46112
_logger.LogDebug($"Handling document symbols for {request.TextDocument.Uri}");
47113

48114
ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri);
49-
List<SymbolInformationOrDocumentSymbol> symbols = new();
115+
List<DocumentSymbol> symbols = new();
50116

51117
foreach (SymbolReference r in ProvideDocumentSymbols(scriptFile))
52118
{
@@ -71,18 +137,31 @@ public override async Task<SymbolInformationOrDocumentSymbolContainer> Handle(Do
71137
// symbols, and we don't have the information nor algorithm to do that currently.
72138
// OmniSharp was previously doing this for us based on the range, perhaps we can
73139
// find that logic and reuse it.
74-
symbols.Add(new SymbolInformationOrDocumentSymbol(newDocumentSymbol
140+
symbols.Add(new DocumentSymbol
75141
{
76142
Kind = SymbolTypeUtils.GetSymbolKind(r.Type),
77143
Range = r.ScriptRegion.ToRange(),
78144
SelectionRange = r.NameRegion.ToRange(),
79145
Name = r.Name
80-
}));
146+
});
147+
}
148+
149+
// Short-circuit if we have no symbols.
150+
if (symbols.Count == 0)
151+
{
152+
return s_emptySymbolInformationOrDocumentSymbolContainer;
81153
}
82154

83-
return symbols.Count == 0
84-
? s_emptySymbolInformationOrDocumentSymbolContainer
85-
: new SymbolInformationOrDocumentSymbolContainer(symbols);
155+
// Otherwise slowly sort them into a hierarchy.
156+
symbols = await SortDocumentSymbols(symbols, cancellationToken).ConfigureAwait(false);
157+
158+
// And finally convert them to the silly SymbolInformationOrDocumentSymbol wrapper.
159+
List<SymbolInformationOrDocumentSymbol> container = new();
160+
foreach (DocumentSymbol symbol in symbols)
161+
{
162+
container.Add(new SymbolInformationOrDocumentSymbol(symbol));
163+
}
164+
return container;
86165
}
87166

88167
private IEnumerable<SymbolReference> ProvideDocumentSymbols(ScriptFile scriptFile)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /