diff --git a/src/PowerShellEditorServices/Server/PsesLanguageServer.cs b/src/PowerShellEditorServices/Server/PsesLanguageServer.cs
index 440e84a70..74319e828 100644
--- a/src/PowerShellEditorServices/Server/PsesLanguageServer.cs
+++ b/src/PowerShellEditorServices/Server/PsesLanguageServer.cs
@@ -70,7 +70,9 @@ public PsesLanguageServer(
/// cref="PsesServiceCollectionExtensions.AddPsesLanguageServices"/>.
///
/// A task that completes when the server is ready and listening.
+#pragma warning disable CA1506 // Coupling complexity we don't care about
public async Task StartAsync()
+#pragma warning restore CA1506
{
LanguageServer = await OmniSharp.Extensions.LanguageServer.Server.LanguageServer.From(options =>
{
diff --git a/src/PowerShellEditorServices/Services/Analysis/PssaCmdletAnalysisEngine.cs b/src/PowerShellEditorServices/Services/Analysis/PssaCmdletAnalysisEngine.cs
index 371950bc0..05f4de8b9 100644
--- a/src/PowerShellEditorServices/Services/Analysis/PssaCmdletAnalysisEngine.cs
+++ b/src/PowerShellEditorServices/Services/Analysis/PssaCmdletAnalysisEngine.cs
@@ -123,6 +123,7 @@ private PssaCmdletAnalysisEngine(
///
/// Format a script given its contents.
+ /// TODO: This needs to be cancellable.
///
/// The full text of a script.
/// The formatter settings to use.
diff --git a/src/PowerShellEditorServices/Services/CodeLens/ICodeLensProvider.cs b/src/PowerShellEditorServices/Services/CodeLens/ICodeLensProvider.cs
index a6255a41d..8ee6bc8b7 100644
--- a/src/PowerShellEditorServices/Services/CodeLens/ICodeLensProvider.cs
+++ b/src/PowerShellEditorServices/Services/CodeLens/ICodeLensProvider.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
@@ -26,9 +27,8 @@ internal interface ICodeLensProvider
///
/// The document for which CodeLenses should be provided.
///
- ///
- /// An array of CodeLenses.
- CodeLens[] ProvideCodeLenses(ScriptFile scriptFile, CancellationToken cancellationToken);
+ /// An IEnumerable of CodeLenses.
+ IEnumerable ProvideCodeLenses(ScriptFile scriptFile);
///
/// Resolves a CodeLens that was created without a Command.
diff --git a/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs b/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs
index 50ddcfc22..22b563b1d 100644
--- a/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs
+++ b/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs
@@ -1,6 +1,5 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@@ -97,21 +96,17 @@ private static CodeLens[] GetPesterLens(PesterSymbolReference pesterSymbol, Scri
/// Get all Pester CodeLenses for a given script file.
///
/// The script file to get Pester CodeLenses for.
- ///
/// All Pester CodeLenses for the given script file.
- public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile, CancellationToken cancellationToken)
+ public IEnumerable ProvideCodeLenses(ScriptFile scriptFile)
{
// Don't return anything if codelens setting is disabled
if (!_configurationService.CurrentSettings.Pester.CodeLens)
{
- return Array.Empty();
+ yield break;
}
- List lenses = new();
foreach (SymbolReference symbol in _symbolProvider.ProvideDocumentSymbols(scriptFile))
{
- cancellationToken.ThrowIfCancellationRequested();
-
if (symbol is not PesterSymbolReference pesterSymbol)
{
continue;
@@ -129,10 +124,11 @@ public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile, CancellationToken can
continue;
}
- lenses.AddRange(GetPesterLens(pesterSymbol, scriptFile));
+ foreach (CodeLens codeLens in GetPesterLens(pesterSymbol, scriptFile))
+ {
+ yield return codeLens;
+ }
}
-
- return lenses.ToArray();
}
///
diff --git a/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs b/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs
index 6e1e4cc81..0307163cc 100644
--- a/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs
+++ b/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs
@@ -52,14 +52,11 @@ public ReferencesCodeLensProvider(WorkspaceService workspaceService, SymbolsServ
/// Get all reference code lenses for a given script file.
///
/// The PowerShell script file to get code lenses for.
- ///
- /// An array of CodeLenses describing all functions, classes and enums in the given script file.
- public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile, CancellationToken cancellationToken)
+ /// An IEnumerable of CodeLenses describing all functions, classes and enums in the given script file.
+ public IEnumerable ProvideCodeLenses(ScriptFile scriptFile)
{
- List acc = new();
foreach (SymbolReference symbol in _symbolProvider.ProvideDocumentSymbols(scriptFile))
{
- cancellationToken.ThrowIfCancellationRequested();
// TODO: Can we support more here?
if (symbol.IsDeclaration &&
symbol.Type is
@@ -67,7 +64,7 @@ SymbolType.Function or
SymbolType.Class or
SymbolType.Enum)
{
- acc.Add(new CodeLens
+ yield return new CodeLens
{
Data = JToken.FromObject(new
{
@@ -75,11 +72,9 @@ SymbolType.Class or
ProviderId = nameof(ReferencesCodeLensProvider)
}, LspSerializer.Instance.JsonSerializer),
Range = symbol.NameRegion.ToRange(),
- });
+ };
}
}
-
- return acc.ToArray();
}
///
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Utility/CommandHelpers.cs b/src/PowerShellEditorServices/Services/PowerShell/Utility/CommandHelpers.cs
index 7750aa042..38a581bec 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Utility/CommandHelpers.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Utility/CommandHelpers.cs
@@ -244,6 +244,11 @@ public static async Task GetAliasesAsync(
foreach (AliasInfo aliasInfo in aliases.Cast())
{
+ if (cancellationToken.IsCancellationRequested)
+ {
+ break;
+ }
+
// TODO: When we move to netstandard2.1, we can use another overload which generates
// static delegates and thus reduces allocations.
s_cmdletToAliasCache.AddOrUpdate(
diff --git a/src/PowerShellEditorServices/Services/Symbols/PesterDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Services/Symbols/PesterDocumentSymbolProvider.cs
index dcf675975..ebc2e720f 100644
--- a/src/PowerShellEditorServices/Services/Symbols/PesterDocumentSymbolProvider.cs
+++ b/src/PowerShellEditorServices/Services/Symbols/PesterDocumentSymbolProvider.cs
@@ -54,7 +54,7 @@ commandAst.InvocationOperator is not (TokenKind.Dot or TokenKind.Ampersand) &&
/// true if the CommandAst represents a Pester command, false otherwise
private static bool IsPesterCommand(CommandAst commandAst)
{
- if (commandAst == null)
+ if (commandAst is null)
{
return false;
}
@@ -94,7 +94,7 @@ private static PesterSymbolReference ConvertPesterAstToSymbolReference(ScriptFil
string commandName = CommandHelpers.StripModuleQualification(pesterCommandAst.GetCommandName(), out _);
PesterCommandType? commandType = PesterSymbolReference.GetCommandType(commandName);
- if (commandType == null)
+ if (commandType is null)
{
return null;
}
@@ -247,10 +247,11 @@ internal PesterSymbolReference(
internal static PesterCommandType? GetCommandType(string commandName)
{
- if (commandName == null || !PesterKeywords.TryGetValue(commandName, out PesterCommandType pesterCommandType))
+ if (commandName is null || !PesterKeywords.TryGetValue(commandName, out PesterCommandType pesterCommandType))
{
return null;
}
+
return pesterCommandType;
}
diff --git a/src/PowerShellEditorServices/Services/Symbols/RegionDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Services/Symbols/RegionDocumentSymbolProvider.cs
new file mode 100644
index 000000000..e3b33b076
--- /dev/null
+++ b/src/PowerShellEditorServices/Services/Symbols/RegionDocumentSymbolProvider.cs
@@ -0,0 +1,79 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+using System.Management.Automation.Language;
+using Microsoft.PowerShell.EditorServices.Services.TextDocument;
+
+namespace Microsoft.PowerShell.EditorServices.Services.Symbols
+{
+ ///
+ /// Provides an IDocumentSymbolProvider implementation for
+ /// enumerating regions as symbols in script (.psd1, .psm1) files.
+ ///
+ internal class RegionDocumentSymbolProvider : IDocumentSymbolProvider
+ {
+ string IDocumentSymbolProvider.ProviderId => nameof(RegionDocumentSymbolProvider);
+
+ IEnumerable IDocumentSymbolProvider.ProvideDocumentSymbols(ScriptFile scriptFile)
+ {
+ Stack tokenCommentRegionStack = new();
+ Token[] tokens = scriptFile.ScriptTokens;
+
+ for (int i = 0; i < tokens.Length; i++)
+ {
+ Token token = tokens[i];
+
+ // Exclude everything but single-line comments
+ if (token.Kind != TokenKind.Comment ||
+ token.Extent.StartLineNumber != token.Extent.EndLineNumber ||
+ !TokenOperations.IsBlockComment(i, tokens))
+ {
+ continue;
+ }
+
+ // Processing for #region -> #endregion
+ if (TokenOperations.s_startRegionTextRegex.IsMatch(token.Text))
+ {
+ tokenCommentRegionStack.Push(token);
+ continue;
+ }
+
+ if (TokenOperations.s_endRegionTextRegex.IsMatch(token.Text))
+ {
+ // Mismatched regions in the script can cause bad stacks.
+ if (tokenCommentRegionStack.Count > 0)
+ {
+ Token regionStart = tokenCommentRegionStack.Pop();
+ Token regionEnd = token;
+
+ BufferRange regionRange = new(
+ regionStart.Extent.StartLineNumber,
+ regionStart.Extent.StartColumnNumber,
+ regionEnd.Extent.EndLineNumber,
+ regionEnd.Extent.EndColumnNumber);
+
+ yield return new SymbolReference(
+ SymbolType.Region,
+ regionStart.Extent.Text.Trim().TrimStart('#'),
+ regionStart.Extent.Text.Trim(),
+ regionStart.Extent,
+ new ScriptExtent()
+ {
+ Text = string.Join(System.Environment.NewLine, scriptFile.GetLinesInRange(regionRange)),
+ StartLineNumber = regionStart.Extent.StartLineNumber,
+ StartColumnNumber = regionStart.Extent.StartColumnNumber,
+ StartOffset = regionStart.Extent.StartOffset,
+ EndLineNumber = regionEnd.Extent.EndLineNumber,
+ EndColumnNumber = regionEnd.Extent.EndColumnNumber,
+ EndOffset = regionEnd.Extent.EndOffset,
+ File = regionStart.Extent.File
+ },
+ scriptFile,
+ isDeclaration: true);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/PowerShellEditorServices/Services/Symbols/SymbolDetails.cs b/src/PowerShellEditorServices/Services/Symbols/SymbolDetails.cs
index ddca0f0a7..dc0a57fcd 100644
--- a/src/PowerShellEditorServices/Services/Symbols/SymbolDetails.cs
+++ b/src/PowerShellEditorServices/Services/Symbols/SymbolDetails.cs
@@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Management.Automation;
+using System.Threading;
using System.Threading.Tasks;
using Microsoft.PowerShell.EditorServices.Services.PowerShell;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Runspace;
@@ -37,7 +38,8 @@ internal class SymbolDetails
internal static async Task CreateAsync(
SymbolReference symbolReference,
IRunspaceInfo currentRunspace,
- IInternalPowerShellExecutionService executionService)
+ IInternalPowerShellExecutionService executionService,
+ CancellationToken cancellationToken)
{
SymbolDetails symbolDetails = new()
{
@@ -49,14 +51,16 @@ internal static async Task CreateAsync(
CommandInfo commandInfo = await CommandHelpers.GetCommandInfoAsync(
symbolReference.Id,
currentRunspace,
- executionService).ConfigureAwait(false);
+ executionService,
+ cancellationToken).ConfigureAwait(false);
if (commandInfo is not null)
{
symbolDetails.Documentation =
await CommandHelpers.GetCommandSynopsisAsync(
commandInfo,
- executionService).ConfigureAwait(false);
+ executionService,
+ cancellationToken).ConfigureAwait(false);
if (commandInfo.CommandType == CommandTypes.Application)
{
diff --git a/src/PowerShellEditorServices/Services/Symbols/SymbolType.cs b/src/PowerShellEditorServices/Services/Symbols/SymbolType.cs
index 6533e7726..02e34e6f8 100644
--- a/src/PowerShellEditorServices/Services/Symbols/SymbolType.cs
+++ b/src/PowerShellEditorServices/Services/Symbols/SymbolType.cs
@@ -79,6 +79,11 @@ internal enum SymbolType
/// The symbol is a type reference
///
Type,
+
+ ///
+ /// The symbol is a region. Only used for navigation-features.
+ ///
+ Region
}
internal static class SymbolTypeUtils
@@ -97,6 +102,7 @@ internal static SymbolKind GetSymbolKind(SymbolType symbolType)
SymbolType.Variable or SymbolType.Parameter => SymbolKind.Variable,
SymbolType.HashtableKey => SymbolKind.Key,
SymbolType.Type => SymbolKind.TypeParameter,
+ SymbolType.Region => SymbolKind.String,
SymbolType.Unknown or _ => SymbolKind.Object,
};
}
diff --git a/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs b/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs
index cf4040642..457b1d651 100644
--- a/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs
+++ b/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs
@@ -77,13 +77,13 @@ public SymbolsService(
PesterCodeLensProvider pesterProvider = new(configurationService);
_ = _codeLensProviders.TryAdd(pesterProvider.ProviderId, pesterProvider);
- // TODO: Is this complication so necessary?
_documentSymbolProviders = new ConcurrentDictionary();
IDocumentSymbolProvider[] documentSymbolProviders = new IDocumentSymbolProvider[]
{
new ScriptDocumentSymbolProvider(),
new PsdDocumentSymbolProvider(),
- new PesterDocumentSymbolProvider(),
+ new PesterDocumentSymbolProvider()
+ // NOTE: This specifically does not include RegionDocumentSymbolProvider.
};
foreach (IDocumentSymbolProvider documentSymbolProvider in documentSymbolProviders)
@@ -187,7 +187,11 @@ public async Task> ScanForReferencesOfSymbolAsync(
foreach (string targetIdentifier in allIdentifiers)
{
await Task.Yield();
- cancellationToken.ThrowIfCancellationRequested();
+ if (cancellationToken.IsCancellationRequested)
+ {
+ break;
+ }
+
symbols.AddRange(file.References.TryGetReferences(symbol with { Id = targetIdentifier }));
}
}
@@ -218,12 +222,16 @@ public static IEnumerable FindOccurrencesInFile(
/// Finds the details of the symbol at the given script file location.
///
public Task FindSymbolDetailsAtLocationAsync(
- ScriptFile scriptFile, int line, int column)
+ ScriptFile scriptFile, int line, int column, CancellationToken cancellationToken)
{
SymbolReference? symbol = FindSymbolAtLocation(scriptFile, line, column);
return symbol is null
? Task.FromResult(null)
- : SymbolDetails.CreateAsync(symbol, _runspaceContext.CurrentRunspace, _executionService);
+ : SymbolDetails.CreateAsync(
+ symbol,
+ _runspaceContext.CurrentRunspace,
+ _executionService,
+ cancellationToken);
}
///
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs
index 2861fe27f..5606c80fa 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs
@@ -19,6 +19,7 @@ namespace Microsoft.PowerShell.EditorServices.Handlers
{
internal class PsesCodeActionHandler : CodeActionHandlerBase
{
+ private static readonly CommandOrCodeActionContainer s_emptyCommandOrCodeActionContainer = new();
private readonly ILogger _logger;
private readonly AnalysisService _analysisService;
@@ -42,16 +43,17 @@ public override async Task Handle(CodeActionParams
if (cancellationToken.IsCancellationRequested)
{
_logger.LogDebug($"CodeAction request canceled at range: {request.Range}");
- return Array.Empty();
+ return s_emptyCommandOrCodeActionContainer;
}
IReadOnlyDictionary> corrections = await _analysisService.GetMostRecentCodeActionsForFileAsync(
request.TextDocument.Uri)
.ConfigureAwait(false);
- if (corrections == null)
+ // GetMostRecentCodeActionsForFileAsync actually returns null if there's no corrections.
+ if (corrections is null)
{
- return Array.Empty();
+ return s_emptyCommandOrCodeActionContainer;
}
List codeActions = new();
@@ -59,6 +61,11 @@ public override async Task Handle(CodeActionParams
// If there are any code fixes, send these commands first so they appear at top of "Code Fix" menu in the client UI.
foreach (Diagnostic diagnostic in request.Context.Diagnostics)
{
+ if (cancellationToken.IsCancellationRequested)
+ {
+ break;
+ }
+
if (string.IsNullOrEmpty(diagnostic.Code?.String))
{
_logger.LogWarning(
@@ -100,8 +107,7 @@ public override async Task Handle(CodeActionParams
HashSet ruleNamesProcessed = new();
foreach (Diagnostic diagnostic in request.Context.Diagnostics)
{
- if (
- !diagnostic.Code.HasValue ||
+ if (!diagnostic.Code.HasValue ||
!diagnostic.Code.Value.IsString ||
string.IsNullOrEmpty(diagnostic.Code?.String))
{
@@ -134,7 +140,9 @@ public override async Task Handle(CodeActionParams
}
}
- return codeActions;
+ return codeActions.Count == 0
+ ? s_emptyCommandOrCodeActionContainer
+ : codeActions;
}
}
}
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs
index 6ac18df8e..407b0d3a0 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs
@@ -3,13 +3,11 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.PowerShell.EditorServices.CodeLenses;
-using Microsoft.PowerShell.EditorServices.Logging;
using Microsoft.PowerShell.EditorServices.Services;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
using Microsoft.PowerShell.EditorServices.Utility;
@@ -21,6 +19,7 @@ namespace Microsoft.PowerShell.EditorServices.Handlers
{
internal class PsesCodeLensHandlers : CodeLensHandlerBase
{
+ private static readonly CodeLensContainer s_emptyCodeLensContainer = new();
private readonly ILogger _logger;
private readonly SymbolsService _symbolsService;
private readonly WorkspaceService _workspaceService;
@@ -40,12 +39,17 @@ public PsesCodeLensHandlers(ILoggerFactory factory, SymbolsService symbolsServic
public override Task Handle(CodeLensParams request, CancellationToken cancellationToken)
{
+ _logger.LogDebug($"Handling code lens request for {request.TextDocument.Uri}");
+
ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri);
- CodeLens[] codeLensResults = ProvideCodeLenses(scriptFile, cancellationToken);
- return Task.FromResult(new CodeLensContainer(codeLensResults));
+ IEnumerable codeLensResults = ProvideCodeLenses(scriptFile);
+
+ return cancellationToken.IsCancellationRequested
+ ? Task.FromResult(s_emptyCodeLensContainer)
+ : Task.FromResult(new CodeLensContainer(codeLensResults));
}
- public override async Task Handle(CodeLens request, CancellationToken cancellationToken)
+ public override Task Handle(CodeLens request, CancellationToken cancellationToken)
{
// TODO: Catch deserialization exception on bad object
CodeLensData codeLensData = request.Data.ToObject();
@@ -55,53 +59,23 @@ public override async Task Handle(CodeLens request, CancellationToken
.FirstOrDefault(provider => provider.ProviderId.Equals(codeLensData.ProviderId, StringComparison.Ordinal));
ScriptFile scriptFile = _workspaceService.GetFile(codeLensData.Uri);
- return await originalProvider.ResolveCodeLens(request, scriptFile, cancellationToken)
- .ConfigureAwait(false);
+ return originalProvider.ResolveCodeLens(request, scriptFile, cancellationToken);
}
///
/// Get all the CodeLenses for a given script file.
///
/// The PowerShell script file to get CodeLenses for.
- ///
/// All generated CodeLenses for the given script file.
- private CodeLens[] ProvideCodeLenses(ScriptFile scriptFile, CancellationToken cancellationToken)
+ private IEnumerable ProvideCodeLenses(ScriptFile scriptFile)
{
- return InvokeProviders(provider => provider.ProvideCodeLenses(scriptFile, cancellationToken))
- .SelectMany(codeLens => codeLens)
- .ToArray();
- }
-
- ///
- /// Invokes the given function synchronously against all
- /// registered providers.
- ///
- /// The function to be invoked.
- ///
- /// An IEnumerable containing the results of all providers
- /// that were invoked successfully.
- ///
- private IEnumerable InvokeProviders(Func invokeFunc)
- {
- Stopwatch invokeTimer = new();
- List providerResults = new();
-
foreach (ICodeLensProvider provider in _symbolsService.GetCodeLensProviders())
{
- try
+ foreach (CodeLens codeLens in provider.ProvideCodeLenses(scriptFile))
{
- invokeTimer.Restart();
- providerResults.Add(invokeFunc(provider));
- invokeTimer.Stop();
- _logger.LogTrace($"Invocation of provider '{provider.GetType().Name}' completed in {invokeTimer.ElapsedMilliseconds}ms.");
- }
- catch (Exception e)
- {
- _logger.LogException($"Exception caught while invoking provider {provider.GetType().Name}:", e);
+ yield return codeLens;
}
}
-
- return providerResults;
}
}
}
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs
index f39ca9917..2519891f5 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs
@@ -17,6 +17,7 @@ namespace Microsoft.PowerShell.EditorServices.Handlers
{
internal class PsesDefinitionHandler : DefinitionHandlerBase
{
+ private static readonly LocationOrLocationLinks s_emptyLocationOrLocationLinks = new();
private readonly SymbolsService _symbolsService;
private readonly WorkspaceService _workspaceService;
@@ -45,20 +46,19 @@ public override async Task Handle(DefinitionParams requ
if (foundSymbol is null)
{
- return new LocationOrLocationLinks();
+ return s_emptyLocationOrLocationLinks;
}
// Short-circuit if we're already on the definition.
if (foundSymbol.IsDeclaration)
{
- return new LocationOrLocationLinks(
- new LocationOrLocationLink[] {
- new LocationOrLocationLink(
- new Location
- {
- Uri = DocumentUri.From(foundSymbol.FilePath),
- Range = foundSymbol.NameRegion.ToRange()
- })});
+ return new LocationOrLocationLink[] {
+ new LocationOrLocationLink(
+ new Location
+ {
+ Uri = DocumentUri.From(foundSymbol.FilePath),
+ Range = foundSymbol.NameRegion.ToRange()
+ })};
}
List definitionLocations = new();
@@ -74,7 +74,9 @@ public override async Task Handle(DefinitionParams requ
}));
}
- return new LocationOrLocationLinks(definitionLocations);
+ return definitionLocations.Count == 0
+ ? s_emptyLocationOrLocationLinks
+ : definitionLocations;
}
}
}
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs
index 5758e59a1..0e470d46f 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs
@@ -45,11 +45,6 @@ public override Task Handle(
request.Position.Line + 1,
request.Position.Character + 1);
- if (occurrences is null)
- {
- return Task.FromResult(s_emptyHighlightContainer);
- }
-
List highlights = new();
foreach (SymbolReference occurrence in occurrences)
{
@@ -62,7 +57,9 @@ public override Task Handle(
_logger.LogDebug("Highlights: " + highlights);
- return Task.FromResult(new DocumentHighlightContainer(highlights));
+ return cancellationToken.IsCancellationRequested || highlights.Count == 0
+ ? Task.FromResult(s_emptyHighlightContainer)
+ : Task.FromResult(new DocumentHighlightContainer(highlights));
}
}
}
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs
index 823d01f26..c6a24bc1b 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs
@@ -1,15 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
-using Microsoft.PowerShell.EditorServices.Logging;
using Microsoft.PowerShell.EditorServices.Services;
using Microsoft.PowerShell.EditorServices.Services.Symbols;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
@@ -23,6 +19,7 @@ namespace Microsoft.PowerShell.EditorServices.Handlers
{
internal class PsesDocumentSymbolHandler : DocumentSymbolHandlerBase
{
+ private static readonly SymbolInformationOrDocumentSymbolContainer s_emptySymbolInformationOrDocumentSymbolContainer = new();
private readonly ILogger _logger;
private readonly WorkspaceService _workspaceService;
private readonly IDocumentSymbolProvider[] _providers;
@@ -35,7 +32,8 @@ public PsesDocumentSymbolHandler(ILoggerFactory factory, WorkspaceService worksp
{
new ScriptDocumentSymbolProvider(),
new PsdDocumentSymbolProvider(),
- new PesterDocumentSymbolProvider()
+ new PesterDocumentSymbolProvider(),
+ new RegionDocumentSymbolProvider()
};
}
@@ -47,23 +45,21 @@ public PsesDocumentSymbolHandler(ILoggerFactory factory, WorkspaceService worksp
// AKA the outline feature
public override async Task Handle(DocumentSymbolParams request, CancellationToken cancellationToken)
{
- ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri);
-
- IEnumerable foundSymbols = ProvideDocumentSymbols(scriptFile);
- if (foundSymbols is null)
- {
- return null;
- }
+ _logger.LogDebug($"Handling document symbols for {request.TextDocument.Uri}");
+ ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri);
string containerName = Path.GetFileNameWithoutExtension(scriptFile.FilePath);
-
List symbols = new();
- foreach (SymbolReference r in foundSymbols)
+
+ foreach (SymbolReference r in ProvideDocumentSymbols(scriptFile))
{
// This async method is pretty dense with synchronous code
// so it's helpful to add some yields.
await Task.Yield();
- cancellationToken.ThrowIfCancellationRequested();
+ if (cancellationToken.IsCancellationRequested)
+ {
+ break;
+ }
// Outline view should only include declarations.
//
@@ -92,58 +88,27 @@ public override async Task Handle(Do
Location = new Location
{
Uri = DocumentUri.From(r.FilePath),
- Range = new Range(r.NameRegion.ToRange().Start, r.ScriptRegion.ToRange().End) // Jump to name start, but keep whole range to support symbol tree in outline
+ // Jump to name start, but keep whole range to support symbol tree in outline
+ Range = new Range(r.NameRegion.ToRange().Start, r.ScriptRegion.ToRange().End)
},
Name = r.Name
}));
}
- return new SymbolInformationOrDocumentSymbolContainer(symbols);
+ return symbols.Count == 0
+ ? s_emptySymbolInformationOrDocumentSymbolContainer
+ : new SymbolInformationOrDocumentSymbolContainer(symbols);
}
private IEnumerable ProvideDocumentSymbols(ScriptFile scriptFile)
{
- return InvokeProviders(p => p.ProvideDocumentSymbols(scriptFile))
- .SelectMany(r => r);
- }
-
- ///
- /// Invokes the given function synchronously against all
- /// registered providers.
- ///
- /// The function to be invoked.
- ///
- /// An IEnumerable containing the results of all providers
- /// that were invoked successfully.
- ///
- protected IEnumerable InvokeProviders(
- Func invokeFunc)
- {
- Stopwatch invokeTimer = new();
- List providerResults = new();
-
foreach (IDocumentSymbolProvider provider in _providers)
{
- try
+ foreach (SymbolReference symbol in provider.ProvideDocumentSymbols(scriptFile))
{
- invokeTimer.Restart();
-
- providerResults.Add(invokeFunc(provider));
-
- invokeTimer.Stop();
-
- _logger.LogTrace(
- $"Invocation of provider '{provider.GetType().Name}' completed in {invokeTimer.ElapsedMilliseconds}ms.");
- }
- catch (Exception e)
- {
- _logger.LogException(
- $"Exception caught while invoking provider {provider.GetType().Name}:",
- e);
+ yield return symbol;
}
}
-
- return providerResults;
}
}
}
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs
index fbf5ad9a5..85593447c 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs
@@ -16,6 +16,7 @@ namespace Microsoft.PowerShell.EditorServices.Handlers
{
internal class PsesFoldingRangeHandler : FoldingRangeHandlerBase
{
+ private static readonly Container s_emptyFoldingRangeContainer = new();
private readonly ILogger _logger;
private readonly ConfigurationService _configurationService;
private readonly WorkspaceService _workspaceService;
@@ -37,27 +38,36 @@ public override Task> Handle(FoldingRangeRequestParam re
if (cancellationToken.IsCancellationRequested)
{
_logger.LogDebug("FoldingRange request canceled for file: {Uri}", request.TextDocument.Uri);
- return Task.FromResult(new Container());
+ return Task.FromResult(s_emptyFoldingRangeContainer);
}
- // TODO Should be using dynamic registrations
- if (!_configurationService.CurrentSettings.CodeFolding.Enable) { return Task.FromResult(new Container()); }
+ // TODO: Should be using dynamic registrations
+ if (!_configurationService.CurrentSettings.CodeFolding.Enable)
+ {
+ return Task.FromResult(s_emptyFoldingRangeContainer);
+ }
// Avoid crash when using untitled: scheme or any other scheme where the document doesn't
// have a backing file. https://github.com/PowerShell/vscode-powershell/issues/1676
// Perhaps a better option would be to parse the contents of the document as a string
// as opposed to reading a file but the scenario of "no backing file" probably doesn't
// warrant the extra effort.
- if (!_workspaceService.TryGetFile(request.TextDocument.Uri, out ScriptFile scriptFile)) { return Task.FromResult(new Container()); }
-
- List result = new();
+ if (!_workspaceService.TryGetFile(request.TextDocument.Uri, out ScriptFile scriptFile))
+ {
+ return Task.FromResult(s_emptyFoldingRangeContainer);
+ }
// If we're showing the last line, decrement the Endline of all regions by one.
int endLineOffset = _configurationService.CurrentSettings.CodeFolding.ShowLastLine ? -1 : 0;
-
+ List folds = new();
foreach (FoldingReference fold in TokenOperations.FoldableReferences(scriptFile.ScriptTokens).References)
{
- result.Add(new FoldingRange
+ if (cancellationToken.IsCancellationRequested)
+ {
+ break;
+ }
+
+ folds.Add(new FoldingRange
{
EndCharacter = fold.EndCharacter,
EndLine = fold.EndLine + endLineOffset,
@@ -67,7 +77,9 @@ public override Task> Handle(FoldingRangeRequestParam re
});
}
- return Task.FromResult(new Container(result));
+ return folds.Count == 0
+ ? Task.FromResult(s_emptyFoldingRangeContainer)
+ : Task.FromResult(new Container(folds));
}
}
}
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs
index 5b72f25cd..64ccb3156 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs
@@ -15,6 +15,7 @@ namespace Microsoft.PowerShell.EditorServices.Handlers
// TODO: Add IDocumentOnTypeFormatHandler to support on-type formatting.
internal class PsesDocumentFormattingHandler : DocumentFormattingHandlerBase
{
+ private static readonly TextEditContainer s_emptyTextEditContainer = new();
private readonly ILogger _logger;
private readonly AnalysisService _analysisService;
private readonly ConfigurationService _configurationService;
@@ -39,6 +40,12 @@ public PsesDocumentFormattingHandler(
public override async Task Handle(DocumentFormattingParams request, CancellationToken cancellationToken)
{
+ if (cancellationToken.IsCancellationRequested)
+ {
+ _logger.LogDebug($"Formatting request canceled for: {request.TextDocument.Uri}");
+ return s_emptyTextEditContainer;
+ }
+
Services.TextDocument.ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri);
System.Collections.Hashtable pssaSettings = _configurationService.CurrentSettings.CodeFormatting.GetPSSASettingsHashtable(
request.Options.TabSize,
@@ -72,14 +79,15 @@ public override async Task Handle(DocumentFormattingParams re
if (formattedScript is null)
{
- _logger.LogWarning($"Formatting returned null. Not formatting: {scriptFile.DocumentUri}");
- return null;
+ _logger.LogDebug($"Formatting returned null. Not formatting: {scriptFile.DocumentUri}");
+ return s_emptyTextEditContainer;
}
+ // Just in case the user really requested a cancellation.
if (cancellationToken.IsCancellationRequested)
{
- _logger.LogWarning($"Formatting request canceled for: {scriptFile.DocumentUri}");
- return null;
+ _logger.LogDebug($"Formatting request canceled for: {scriptFile.DocumentUri}");
+ return s_emptyTextEditContainer;
}
return new TextEditContainer(new TextEdit
@@ -92,6 +100,7 @@ public override async Task Handle(DocumentFormattingParams re
internal class PsesDocumentRangeFormattingHandler : DocumentRangeFormattingHandlerBase
{
+ private static readonly TextEditContainer s_emptyTextEditContainer = new();
private readonly ILogger _logger;
private readonly AnalysisService _analysisService;
private readonly ConfigurationService _configurationService;
@@ -116,6 +125,12 @@ public PsesDocumentRangeFormattingHandler(
public override async Task Handle(DocumentRangeFormattingParams request, CancellationToken cancellationToken)
{
+ if (cancellationToken.IsCancellationRequested)
+ {
+ _logger.LogDebug($"Formatting request canceled for: {request.TextDocument.Uri}");
+ return s_emptyTextEditContainer;
+ }
+
Services.TextDocument.ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri);
System.Collections.Hashtable pssaSettings = _configurationService.CurrentSettings.CodeFormatting.GetPSSASettingsHashtable(
request.Options.TabSize,
@@ -158,14 +173,15 @@ public override async Task Handle(DocumentRangeFormattingPara
if (formattedScript is null)
{
- _logger.LogWarning($"Formatting returned null. Not formatting: {scriptFile.DocumentUri}");
- return null;
+ _logger.LogDebug($"Formatting returned null. Not formatting: {scriptFile.DocumentUri}");
+ return s_emptyTextEditContainer;
}
+ // Just in case the user really requested a cancellation.
if (cancellationToken.IsCancellationRequested)
{
- _logger.LogWarning($"Formatting request canceled for: {scriptFile.DocumentUri}");
- return null;
+ _logger.LogDebug($"Formatting request canceled for: {scriptFile.DocumentUri}");
+ return s_emptyTextEditContainer;
}
return new TextEditContainer(new TextEdit
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/HoverHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/HoverHandler.cs
index 567da0159..9da05490a 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/HoverHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/HoverHandler.cs
@@ -50,7 +50,8 @@ public override async Task Handle(HoverParams request, CancellationToken
await _symbolsService.FindSymbolDetailsAtLocationAsync(
scriptFile,
request.Position.Line + 1,
- request.Position.Character + 1).ConfigureAwait(false);
+ request.Position.Character + 1,
+ cancellationToken).ConfigureAwait(false);
if (symbolDetails is null)
{
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs
index 1d41f3571..c7297e16f 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs
@@ -17,6 +17,7 @@ namespace Microsoft.PowerShell.EditorServices.Handlers
{
internal class PsesReferencesHandler : ReferencesHandlerBase
{
+ private static readonly LocationContainer s_emptyLocationContainer = new();
private readonly SymbolsService _symbolsService;
private readonly WorkspaceService _workspaceService;
@@ -33,6 +34,11 @@ public PsesReferencesHandler(SymbolsService symbolsService, WorkspaceService wor
public override async Task Handle(ReferenceParams request, CancellationToken cancellationToken)
{
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return s_emptyLocationContainer;
+ }
+
ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri);
SymbolReference foundSymbol =
@@ -45,6 +51,11 @@ public override async Task Handle(ReferenceParams request, Ca
foreach (SymbolReference foundReference in await _symbolsService.ScanForReferencesOfSymbolAsync(
foundSymbol, cancellationToken).ConfigureAwait(false))
{
+ if (cancellationToken.IsCancellationRequested)
+ {
+ break;
+ }
+
// Respect the request's setting to include declarations.
if (!request.Context.IncludeDeclaration && foundReference.IsDeclaration)
{
@@ -58,7 +69,9 @@ public override async Task Handle(ReferenceParams request, Ca
});
}
- return new LocationContainer(locations);
+ return locations.Count == 0
+ ? s_emptyLocationContainer
+ : locations;
}
}
}
diff --git a/src/PowerShellEditorServices/Services/TextDocument/TokenOperations.cs b/src/PowerShellEditorServices/Services/TextDocument/TokenOperations.cs
index 4299993f7..6a6f789ff 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/TokenOperations.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/TokenOperations.cs
@@ -17,9 +17,9 @@ internal static class TokenOperations
// script. They are based on the defaults in the VS Code Language Configuration at;
// https://github.com/Microsoft/vscode/blob/64186b0a26/extensions/powershell/language-configuration.json#L26-L31
// https://github.com/Microsoft/vscode/issues/49070
- private static readonly Regex s_startRegionTextRegex = new(
+ internal static readonly Regex s_startRegionTextRegex = new(
@"^\s*#[rR]egion\b", RegexOptions.Compiled);
- private static readonly Regex s_endRegionTextRegex = new(
+ internal static readonly Regex s_endRegionTextRegex = new(
@"^\s*#[eE]nd[rR]egion\b", RegexOptions.Compiled);
///
@@ -199,7 +199,7 @@ private static FoldingReference CreateFoldingReference(
/// - Token text must start with a '#'.false This is because comment regions
/// start with '<#' but have the same TokenKind
///
- private static bool IsBlockComment(int index, Token[] tokens)
+ internal static bool IsBlockComment(int index, Token[] tokens)
{
Token thisToken = tokens[index];
if (thisToken.Kind != TokenKind.Comment) { return false; }
diff --git a/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs b/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs
index 3efe4edcf..fa7f1d49a 100644
--- a/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs
+++ b/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs
@@ -19,6 +19,7 @@ namespace Microsoft.PowerShell.EditorServices.Handlers
{
internal class PsesWorkspaceSymbolsHandler : WorkspaceSymbolsHandlerBase
{
+ private static readonly Container s_emptySymbolInformationContainer = new();
private readonly ILogger _logger;
private readonly SymbolsService _symbolsService;
private readonly WorkspaceService _workspaceService;
@@ -34,23 +35,26 @@ public PsesWorkspaceSymbolsHandler(ILoggerFactory loggerFactory, SymbolsService
public override async Task> Handle(WorkspaceSymbolParams request, CancellationToken cancellationToken)
{
+ _logger.LogDebug($"Handling workspace symbols request for query {request.Query}");
+
await _symbolsService.ScanWorkspacePSFiles(cancellationToken).ConfigureAwait(false);
List symbols = new();
foreach (ScriptFile scriptFile in _workspaceService.GetOpenedFiles())
{
_logger.LogDebug($"Handling workspace symbols request for: {request.Query}");
- IEnumerable foundSymbols = _symbolsService.FindSymbolsInFile(scriptFile);
-
// TODO: Need to compute a relative path that is based on common path for all workspace files
string containerName = Path.GetFileNameWithoutExtension(scriptFile.FilePath);
- foreach (SymbolReference symbol in foundSymbols)
+ foreach (SymbolReference symbol in _symbolsService.FindSymbolsInFile(scriptFile))
{
// This async method is pretty dense with synchronous code
// so it's helpful to add some yields.
await Task.Yield();
- cancellationToken.ThrowIfCancellationRequested();
+ if (cancellationToken.IsCancellationRequested)
+ {
+ break;
+ }
if (!symbol.IsDeclaration)
{
@@ -91,13 +95,11 @@ public override async Task> Handle(WorkspaceSymbolP
}
}
- return new Container(symbols);
+ return symbols.Count == 0
+ ? s_emptySymbolInformationContainer
+ : symbols;
}
- #region private Methods
-
private static bool IsQueryMatch(string query, string symbolName) => symbolName.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0;
-
- #endregion
}
}
diff --git a/test/PowerShellEditorServices.Test.Shared/Symbols/MultipleSymbols.ps1 b/test/PowerShellEditorServices.Test.Shared/Symbols/MultipleSymbols.ps1
index b4f54c329..2831ea332 100644
--- a/test/PowerShellEditorServices.Test.Shared/Symbols/MultipleSymbols.ps1
+++ b/test/PowerShellEditorServices.Test.Shared/Symbols/MultipleSymbols.ps1
@@ -41,3 +41,16 @@ enum AEnum {
AFunction
1..3 | AFilter
AnAdvancedFunction
+
+<#
+#region don't find me inside comment block
+abc
+#endregion
+#>
+
+#region find me outer
+#region find me inner
+
+#endregion
+#endregion
+#region ignore this unclosed region
diff --git a/test/PowerShellEditorServices.Test/Language/SymbolsServiceTests.cs b/test/PowerShellEditorServices.Test/Language/SymbolsServiceTests.cs
index dbe0f8ca6..109a3667f 100644
--- a/test/PowerShellEditorServices.Test/Language/SymbolsServiceTests.cs
+++ b/test/PowerShellEditorServices.Test/Language/SymbolsServiceTests.cs
@@ -755,7 +755,8 @@ public async Task FindsDetailsForBuiltInCommand()
SymbolDetails symbolDetails = await symbolsService.FindSymbolDetailsAtLocationAsync(
GetScriptFile(FindsDetailsForBuiltInCommandData.SourceDetails),
FindsDetailsForBuiltInCommandData.SourceDetails.StartLineNumber,
- FindsDetailsForBuiltInCommandData.SourceDetails.StartColumnNumber).ConfigureAwait(true);
+ FindsDetailsForBuiltInCommandData.SourceDetails.StartColumnNumber,
+ CancellationToken.None).ConfigureAwait(true);
Assert.Equal("Gets the processes that are running on the local computer.", symbolDetails.Documentation);
}
@@ -821,6 +822,35 @@ public void FindsSymbolsInFile()
Assert.Equal("prop AValue", symbol.Id);
Assert.Equal("AValue", symbol.Name);
Assert.True(symbol.IsDeclaration);
+
+ // There should be no region symbols unless the provider has been registered.
+ Assert.Empty(symbols.Where(i => i.Type == SymbolType.Region));
+ }
+
+ [Fact]
+ public void FindsRegionsInFile()
+ {
+ symbolsService.TryRegisterDocumentSymbolProvider(new RegionDocumentSymbolProvider());
+ IEnumerable symbols = FindSymbolsInFile(FindSymbolsInMultiSymbolFile.SourceDetails);
+ Assert.Collection(symbols.Where(i => i.Type == SymbolType.Region),
+ (i) =>
+ {
+ Assert.Equal("region find me outer", i.Id);
+ Assert.Equal("#region find me outer", i.Name);
+ Assert.Equal(SymbolType.Region, i.Type);
+ Assert.True(i.IsDeclaration);
+ AssertIsRegion(i.NameRegion, 51, 1, 51, 22);
+ AssertIsRegion(i.ScriptRegion, 51, 1, 55, 11);
+ },
+ (i) =>
+ {
+ Assert.Equal("region find me inner", i.Id);
+ Assert.Equal("#region find me inner", i.Name);
+ Assert.Equal(SymbolType.Region, i.Type);
+ Assert.True(i.IsDeclaration);
+ AssertIsRegion(i.NameRegion, 52, 1, 52, 22);
+ AssertIsRegion(i.ScriptRegion, 52, 1, 54, 11);
+ });
}
[Fact]