protected override void CollectBlockSpans( SyntaxToken previousToken, BlockSyntax node, ref TemporaryArray <BlockSpan> spans, BlockStructureOptions options, CancellationToken cancellationToken) { var parentKind = node.Parent.Kind(); // For most types of statements, just consider the block 'attached' to the // parent node. That means we'll show the parent node header when doing // things like hovering over the indent guide. // // This also works nicely as the close brace for these constructs will always // align with the start of these statements. if (IsNonBlockStatement(node.Parent) || parentKind == SyntaxKind.ElseClause) { var type = GetType(node.Parent); if (type != null) { spans.Add(new BlockSpan( isCollapsible: true, textSpan: GetTextSpan(node), hintSpan: GetHintSpan(node), type: type, autoCollapse: parentKind == SyntaxKind.LocalFunctionStatement && node.Parent.IsParentKind(SyntaxKind.GlobalStatement))); } } // Nested blocks aren't attached to anything. Just collapse them as is. // Switch sections are also special. Say you have the following: // // case 0: // { // // } // // We don't want to consider the block parented by the case, because // that would cause us to draw the following: // // case 0: // | { // | // | } // // Which would obviously be wonky. So in this case, we just use the // spanof the block alone, without consideration for the case clause. if (parentKind is SyntaxKind.Block or SyntaxKind.SwitchSection) { var type = GetType(node.Parent); spans.Add(new BlockSpan( isCollapsible: true, textSpan: node.Span, hintSpan: node.Span, type: type)); } }
protected override void CollectBlockSpans( InitializerExpressionSyntax node, ref TemporaryArray <BlockSpan> spans, BlockStructureOptionProvider optionProvider, CancellationToken cancellationToken ) { if (node.Parent is InitializerExpressionSyntax) { // We have something like: // // new Dictionary<int, string> // { // ... // { // ... // }, // ... // } // // In this case, we want to collapse the "{ ... }," (including the comma). var nextToken = node.CloseBraceToken.GetNextToken(); var end = nextToken.Kind() == SyntaxKind.CommaToken ? nextToken.Span.End : node.Span.End; spans.Add( new BlockSpan( isCollapsible: true, textSpan: TextSpan.FromBounds(node.SpanStart, end), hintSpan: TextSpan.FromBounds(node.SpanStart, end), type: BlockTypes.Expression ) ); } else { // Parent is something like: // // new Dictionary<int, string> { // ... // } // // The collapsed textspan should be from the > to the } // // However, the hint span should be the entire object creation. var previousToken = node.OpenBraceToken.GetPreviousToken(); spans.Add( new BlockSpan( isCollapsible: true, textSpan: TextSpan.FromBounds(previousToken.Span.End, node.Span.End), hintSpan: node.Parent.Span, type: BlockTypes.Expression ) ); } }
private async Task UpdateReferencesAsync(Project project, CancellationToken cancellationToken) { // Process all metadata references. If it remote workspace, do this in parallel. using var pendingTasks = new TemporaryArray <Task>(); foreach (var reference in project.MetadataReferences) { if (reference is not PortableExecutableReference portableExecutableReference) { continue; } if (cancellationToken.IsCancellationRequested) { // Break out of this loop to make sure other pending operations process cancellation before // returning. break; } var updateTask = UpdateReferenceAsync(_metadataIdToInfo, project, portableExecutableReference, cancellationToken); if (updateTask.Status != TaskStatus.RanToCompletion) { pendingTasks.Add(updateTask); } } if (pendingTasks.Count > 0) { // If any update operations did not complete synchronously (including any cancelled operations), // wait for them to complete now. await Task.WhenAll(pendingTasks.ToImmutableAndClear()).ConfigureAwait(false); }
protected override void CollectBlockSpans( RegionDirectiveTriviaSyntax regionDirective, ref TemporaryArray <BlockSpan> spans, BlockStructureOptionProvider optionProvider, CancellationToken cancellationToken) { var match = regionDirective.GetMatchingDirective(cancellationToken); if (match != null) { // Always auto-collapse regions for Metadata As Source. These generated files only have one region at // the top of the file, which has content like the following: // // #region Assembly System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a // // C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\3.1.0\ref\netcoreapp3.1\System.Runtime.dll // #endregion // // For other files, auto-collapse regions based on the user option. var autoCollapse = optionProvider.IsMetadataAsSource || optionProvider.GetOption( BlockStructureOptions.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.CSharp); spans.Add(new BlockSpan( isCollapsible: true, textSpan: TextSpan.FromBounds(regionDirective.SpanStart, match.Span.End), type: BlockTypes.PreprocessorRegion, bannerText: GetBannerText(regionDirective), autoCollapse: autoCollapse, isDefaultCollapsed: !optionProvider.IsMetadataAsSource)); } }
protected override void CollectBlockSpans( SyntaxToken previousToken, DocumentationCommentTriviaSyntax documentationComment, ref TemporaryArray <BlockSpan> spans, BlockStructureOptionProvider optionProvider, CancellationToken cancellationToken) { var startPos = documentationComment.FullSpan.Start; // The trailing newline is included in XmlDocCommentSyntax, so we need to strip it. var endPos = documentationComment.SpanStart + documentationComment.ToString().TrimEnd().Length; var span = TextSpan.FromBounds(startPos, endPos); var bannerLength = optionProvider.GetOption(BlockStructureOptions.MaximumBannerLength, LanguageNames.CSharp); var bannerText = CSharpSyntaxFacts.Instance.GetBannerText( documentationComment, bannerLength, cancellationToken); spans.Add(new BlockSpan( isCollapsible: true, textSpan: span, type: BlockTypes.Comment, bannerText: bannerText, autoCollapse: true)); }
protected override void CollectBlockSpans( SyntaxToken previousToken, DocumentationCommentTriviaSyntax documentationComment, ref TemporaryArray <BlockSpan> spans, BlockStructureOptions options, CancellationToken cancellationToken) { // In metadata as source we want to treat documentation comments slightly differently, and collapse them // to just "..." in front of the decalaration they're attached to. That happens in CSharpStructureHelper.CollectCommentBlockSpans // so we don't need to do anything here if (options.IsMetadataAsSource) { return; } var startPos = documentationComment.FullSpan.Start; // The trailing newline is included in XmlDocCommentSyntax, so we need to strip it. var endPos = documentationComment.SpanStart + documentationComment.ToString().TrimEnd().Length; var span = TextSpan.FromBounds(startPos, endPos); var bannerLength = options.MaximumBannerLength; var bannerText = CSharpFileBannerFacts.Instance.GetBannerText( documentationComment, bannerLength, cancellationToken); spans.Add(new BlockSpan( isCollapsible: true, textSpan: span, type: BlockTypes.Comment, bannerText: bannerText, autoCollapse: true)); }
public static void CollectBlockSpans( SyntaxTree syntaxTree, SyntaxTrivia trivia, ref TemporaryArray <BlockSpan> spans, CancellationToken cancellationToken ) { // We'll always be leading trivia of some token. var startPos = trivia.FullSpan.Start; var parentTriviaList = trivia.Token.LeadingTrivia; var indexInParent = parentTriviaList.IndexOf(trivia); // Note: in some error cases (for example when all future tokens end up being skipped) // the parser may end up attaching pre-processor directives as trailing trivia to a // preceding token. if (indexInParent < 0) { parentTriviaList = trivia.Token.TrailingTrivia; indexInParent = parentTriviaList.IndexOf(trivia); } if (indexInParent <= 0) { return; } if ( !parentTriviaList[indexInParent - 1].IsKind(SyntaxKind.IfDirectiveTrivia) && !parentTriviaList[indexInParent - 1].IsKind(SyntaxKind.ElifDirectiveTrivia) && !parentTriviaList[indexInParent - 1].IsKind(SyntaxKind.ElseDirectiveTrivia) ) { return; } var endTrivia = GetCorrespondingEndTrivia(trivia, parentTriviaList, indexInParent); var endPos = GetEndPositionExludingLastNewLine( syntaxTree, endTrivia, cancellationToken ); var span = TextSpan.FromBounds(startPos, endPos); spans.Add( new BlockSpan( isCollapsible: true, textSpan: span, type: BlockTypes.PreprocessorRegion, bannerText: CSharpStructureHelpers.Ellipsis, autoCollapse: true ) ); }
protected override void CollectBlockSpans( SyntaxToken previousToken, ArrowExpressionClauseSyntax node, ref TemporaryArray <BlockSpan> spans, BlockStructureOptionProvider optionProvider, CancellationToken cancellationToken) { spans.Add(new BlockSpan( isCollapsible: true, textSpan: TextSpan.FromBounds(previousToken.Span.End, node.Parent.Span.End), hintSpan: node.Parent.Span, type: BlockTypes.Nonstructural, autoCollapse: !node.IsParentKind(SyntaxKind.LocalFunctionStatement))); }
public static void AddParts(string text, bool word, ref TemporaryArray <TextSpan> parts) { for (var start = 0; start < text.Length;) { var span = StringBreaker.GenerateSpan(text, start, word); if (span.IsEmpty) { // All done break; } Debug.Assert(span.Start >= start, "Bad generator."); parts.Add(span); start = span.End; } }
protected override void CollectBlockSpans( LiteralExpressionSyntax node, ref TemporaryArray <BlockSpan> spans, BlockStructureOptionProvider optionProvider, CancellationToken cancellationToken) { if (node.IsKind(SyntaxKind.StringLiteralExpression) && !node.ContainsDiagnostics) { spans.Add(new BlockSpan( isCollapsible: true, textSpan: node.Span, hintSpan: node.Span, type: BlockTypes.Expression, autoCollapse: true, isDefaultCollapsed: false)); } }
protected override void CollectBlockSpans( InterpolatedStringExpressionSyntax node, ref TemporaryArray <BlockSpan> spans, BlockStructureOptionProvider optionProvider, CancellationToken cancellationToken) { if (node.StringStartToken.IsMissing || node.StringEndToken.IsMissing) { return; } spans.Add(new BlockSpan( isCollapsible: true, textSpan: node.Span, hintSpan: node.Span, type: BlockTypes.Expression, autoCollapse: true, isDefaultCollapsed: false)); }