|
5 | 5 | using System.Threading; |
6 | 6 | using System.Threading.Tasks; |
7 | 7 | using Microsoft.AspNetCore.Razor.Language; |
| 8 | +using Microsoft.AspNetCore.Razor.Language.Syntax; |
8 | 9 | using Microsoft.CodeAnalysis.ExternalAccess.Razor; |
9 | 10 | using Microsoft.CodeAnalysis.Razor.DocumentMapping; |
10 | | -using Microsoft.CodeAnalysis.Razor.Protocol; |
11 | 11 | using Microsoft.CodeAnalysis.Razor.Remote; |
12 | 12 | using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; |
13 | 13 | using Microsoft.CodeAnalysis.Text; |
@@ -113,27 +113,48 @@ protected override IRemoteDebugInfoService CreateService(in ServiceArgs args) |
113 | 113 |
|
114 | 114 | private bool TryGetUsableProjectedIndex(RazorCodeDocument codeDocument, LinePosition hostDocumentPosition, out int projectedIndex) |
115 | 115 | { |
116 | | - var hostDocumentIndex = codeDocument.Source.Text.GetPosition(hostDocumentPosition); |
117 | | - |
118 | 116 | projectedIndex = 0; |
119 | | - var languageKind = codeDocument.GetLanguageKind(hostDocumentIndex, rightAssociative: false); |
120 | | - // For C#, we just map |
121 | | - if (languageKind == RazorLanguageKind.CSharp && |
122 | | - !_documentMappingService.TryMapToCSharpDocumentPosition(codeDocument.GetRequiredCSharpDocument(), hostDocumentIndex, out _, out projectedIndex)) |
123 | | - { |
124 | | - return false; |
125 | | - } |
126 | | - // Otherwise see if there is more C# on the line to map to. This is for situations like "$$<p>@DateTime.Now</p>" |
127 | | - else if (languageKind == RazorLanguageKind.Html && |
128 | | - !_documentMappingService.TryMapToCSharpPositionOrNext(codeDocument.GetRequiredCSharpDocument(), hostDocumentIndex, out _, out projectedIndex)) |
129 | | - { |
130 | | - return false; |
131 | | - } |
132 | | - else if (languageKind == RazorLanguageKind.Razor) |
| 117 | + |
| 118 | + var sourceText = codeDocument.Source.Text; |
| 119 | + var hostDocumentIndex = sourceText.GetPosition(hostDocumentPosition); |
| 120 | + var syntaxRoot = codeDocument.GetRequiredSyntaxRoot(); |
| 121 | + var csharpDocument = codeDocument.GetRequiredCSharpDocument(); |
| 122 | + |
| 123 | + // We want to find a position that maps to C# on the same line as the original request, but we might have to skip over |
| 124 | + // some Razor/HTML nodes to find valid C#. |
| 125 | + while (sourceText.GetLinePosition(hostDocumentIndex).Line == hostDocumentPosition.Line) |
133 | 126 | { |
134 | | - return false; |
| 127 | + if (_documentMappingService.TryMapToCSharpPositionOrNext(csharpDocument, hostDocumentIndex, out _, out projectedIndex)) |
| 128 | + { |
| 129 | + if (syntaxRoot.FindInnermostNode(hostDocumentIndex) is not { } node) |
| 130 | + { |
| 131 | + return false; |
| 132 | + } |
| 133 | + |
| 134 | + // We want to avoid component tags and component attributes, where we map to C#, but they're not valid breakpoint locations |
| 135 | + if (!node.IsAnyAttributeSyntax() && node is not (MarkupTagHelperStartTagSyntax or MarkupEndTagSyntax)) |
| 136 | + { |
| 137 | + // Found something valid! |
| 138 | + return true; |
| 139 | + } |
| 140 | + |
| 141 | + // It's C#, but not valid, so skip past it so we can try to find more C# |
| 142 | + hostDocumentIndex = node.Span.End + 1; |
| 143 | + } |
| 144 | + |
| 145 | + // See if there is more C# on the line to map to, for example "$$<p>@DateTime.Now</p>" |
| 146 | + if (!_documentMappingService.TryMapToCSharpPositionOrNext(csharpDocument, hostDocumentIndex, out _, out projectedIndex)) |
| 147 | + { |
| 148 | + return false; |
| 149 | + } |
| 150 | + |
| 151 | + // We found some C# later on the line, so map that back to Razor so we can loop around and check the node type |
| 152 | + if (!_documentMappingService.TryMapToRazorDocumentPosition(csharpDocument, projectedIndex, out _, out hostDocumentIndex)) |
| 153 | + { |
| 154 | + return false; |
| 155 | + } |
135 | 156 | } |
136 | 157 |
|
137 | | - return true; |
| 158 | + return false; |
138 | 159 | } |
139 | 160 | } |
0 commit comments