5
5
using System . Collections . Immutable ;
6
6
using System . Diagnostics ;
7
7
using Microsoft . AspNetCore . Razor . Language . Intermediate ;
8
+ using Microsoft . AspNetCore . Razor . Utilities ;
8
9
using static Microsoft . AspNetCore . Razor . Language . CodeGeneration . CodeWriterExtensions ;
9
10
10
11
namespace Microsoft . AspNetCore . Razor . Language . CodeGeneration ;
@@ -29,11 +30,12 @@ public static CSharpCodeWritingScope BuildNamespace(this CodeRenderingContext co
29
30
else
30
31
{
31
32
writer . WriteLine ( ) ;
32
- using ( writer . BuildEnhancedLinePragma ( span , context ) )
33
+ using ( context . BuildEnhancedLinePragma ( span ) )
33
34
{
34
35
writer . WriteLine ( name ) ;
35
36
}
36
37
}
38
+
37
39
return new CSharpCodeWritingScope ( writer ) ;
38
40
}
39
41
@@ -81,7 +83,7 @@ public static CSharpCodeWritingScope BuildClassDeclaration(
81
83
82
84
if ( typeParameter . ParameterNameSource is { } source )
83
85
{
84
- WriteWithPragma ( writer , typeParameter . ParameterName , context , source ) ;
86
+ WriteWithPragma ( context , typeParameter . ParameterName , source ) ;
85
87
}
86
88
else
87
89
{
@@ -137,7 +139,7 @@ public static CSharpCodeWritingScope BuildClassDeclaration(
137
139
if ( typeParameter . ConstraintsSource is { } source )
138
140
{
139
141
Debug . Assert ( context != null ) ;
140
- WriteWithPragma ( writer , constraint , context , source ) ;
142
+ WriteWithPragma ( context , constraint , source ) ;
141
143
}
142
144
else
143
145
{
@@ -167,27 +169,29 @@ void WriteToken(IntermediateToken token)
167
169
{
168
170
if ( token . Source is { } source )
169
171
{
170
- WriteWithPragma ( writer , token . Content , context , source ) ;
172
+ WriteWithPragma ( context , token . Content , source ) ;
171
173
}
172
174
else
173
175
{
174
176
writer . Write ( token . Content ) ;
175
177
}
176
178
}
177
179
178
- static void WriteWithPragma ( CodeWriter writer , string content , CodeRenderingContext context , SourceSpan source )
180
+ static void WriteWithPragma ( CodeRenderingContext context , string content , SourceSpan source )
179
181
{
182
+ var writer = context . CodeWriter ;
183
+
180
184
if ( context . Options . DesignTime )
181
185
{
182
- using ( writer . BuildLinePragma ( source , context ) )
186
+ using ( context . BuildLinePragma ( source ) )
183
187
{
184
188
context . AddSourceMappingFor ( source ) ;
185
189
writer . Write ( content ) ;
186
190
}
187
191
}
188
192
else
189
193
{
190
- using ( writer . BuildEnhancedLinePragma ( source , context ) )
194
+ using ( context . BuildEnhancedLinePragma ( source ) )
191
195
{
192
196
writer . Write ( content ) ;
193
197
}
@@ -262,17 +266,152 @@ private static void WritePropertyDeclarationPreamble(
262
266
263
267
static void WriteToken ( CodeRenderingContext context , string content , SourceSpan ? span )
264
268
{
269
+ var writer = context . CodeWriter ;
270
+
265
271
if ( span is not null && context . Options . DesignTime == false )
266
272
{
267
- using ( context . CodeWriter . BuildEnhancedLinePragma ( span , context ) )
273
+ using ( context . BuildEnhancedLinePragma ( span ) )
268
274
{
269
- context . CodeWriter . Write ( content ) ;
275
+ writer . Write ( content ) ;
270
276
}
271
277
}
272
278
else
273
279
{
274
- context . CodeWriter . Write ( content ) ;
280
+ writer . Write ( content ) ;
281
+ }
282
+ }
283
+ }
284
+
285
+ public static LinePragmaScope BuildLinePragma (
286
+ this CodeRenderingContext context ,
287
+ SourceSpan ? span ,
288
+ bool suppressLineDefaultAndHidden = false )
289
+ {
290
+ if ( string . IsNullOrEmpty ( span ? . FilePath ) )
291
+ {
292
+ // Can't build a valid line pragma without a file path.
293
+ return default ;
294
+ }
295
+
296
+ return new LinePragmaScope ( context , span . Value , 0 , useEnhancedLinePragma : false , suppressLineDefaultAndHidden ) ;
297
+ }
298
+
299
+ public static LinePragmaScope BuildEnhancedLinePragma (
300
+ this CodeRenderingContext context ,
301
+ SourceSpan ? span ,
302
+ int characterOffset = 0 ,
303
+ bool suppressLineDefaultAndHidden = false )
304
+ {
305
+ if ( string . IsNullOrEmpty ( span ? . FilePath ) )
306
+ {
307
+ // Can't build a valid line pragma without a file path.
308
+ return default ;
309
+ }
310
+
311
+ return new LinePragmaScope ( context , span . Value , characterOffset , useEnhancedLinePragma : true , suppressLineDefaultAndHidden ) ;
312
+ }
313
+
314
+ public readonly ref struct LinePragmaScope
315
+ {
316
+ private readonly CodeRenderingContext _context ;
317
+ private readonly int _startIndent ;
318
+ private readonly int _startLineIndex ;
319
+ private readonly SourceSpan _span ;
320
+ private readonly bool _suppressLineDefaultAndHidden ;
321
+
322
+ public LinePragmaScope (
323
+ CodeRenderingContext context ,
324
+ SourceSpan span ,
325
+ int characterOffset ,
326
+ bool useEnhancedLinePragma = false ,
327
+ bool suppressLineDefaultAndHidden = false )
328
+ {
329
+ Debug . Assert ( context . Options . DesignTime || useEnhancedLinePragma , "Runtime generation should only use enhanced line pragmas" ) ;
330
+
331
+ _context = context ;
332
+ _suppressLineDefaultAndHidden = suppressLineDefaultAndHidden ;
333
+ _span = span ;
334
+
335
+ var writer = context . CodeWriter ;
336
+ _startIndent = writer . CurrentIndent ;
337
+ writer . CurrentIndent = 0 ;
338
+
339
+ var endsWithNewline = writer . LastChar is '\n ' ;
340
+ if ( ! endsWithNewline )
341
+ {
342
+ writer . WriteLine ( ) ;
343
+ }
344
+
345
+ if ( ! _context . Options . SuppressNullabilityEnforcement )
346
+ {
347
+ writer . WriteLine ( "#nullable restore" ) ;
348
+ }
349
+
350
+ var ensurePathBackslashes = context . Options . RemapLinePragmaPathsOnWindows && PlatformInformation . IsWindows ;
351
+ if ( useEnhancedLinePragma && _context . Options . UseEnhancedLinePragma )
352
+ {
353
+ writer . WriteEnhancedLineNumberDirective ( span , characterOffset , ensurePathBackslashes ) ;
354
+ }
355
+ else
356
+ {
357
+ writer . WriteLineNumberDirective ( span , ensurePathBackslashes ) ;
358
+ }
359
+
360
+ // Capture the line index after writing the #line directive.
361
+ _startLineIndex = writer . Location . LineIndex ;
362
+
363
+ if ( useEnhancedLinePragma )
364
+ {
365
+ // If the caller requested an enhanced line directive, but we fell back to regular ones, write out the extra padding that is required
366
+ if ( ! _context . Options . UseEnhancedLinePragma )
367
+ {
368
+ writer . WritePadding ( 0 , span , context ) ;
369
+ characterOffset = 0 ;
370
+ }
371
+
372
+ context . AddSourceMappingFor ( span , characterOffset ) ;
373
+ }
374
+ }
375
+
376
+ public void Dispose ( )
377
+ {
378
+ if ( _context is null )
379
+ {
380
+ return ;
381
+ }
382
+
383
+ var writer = _context . CodeWriter ;
384
+
385
+ // Need to add an additional line at the end IF there wasn't one already written.
386
+ // This is needed to work with the C# editor's handling of #line ...
387
+ var endsWithNewline = writer . LastChar is '\n ' ;
388
+
389
+ // Always write at least 1 empty line to potentially separate code from pragmas.
390
+ writer . WriteLine ( ) ;
391
+
392
+ // Check if the previous empty line wasn't enough to separate code from pragmas.
393
+ if ( ! endsWithNewline )
394
+ {
395
+ writer . WriteLine ( ) ;
275
396
}
397
+
398
+ var lineCount = writer . Location . LineIndex - _startLineIndex ;
399
+ var linePragma = new LinePragma ( _span . LineIndex , lineCount , _span . FilePath , _span . EndCharacterIndex , _span . EndCharacterIndex , _span . CharacterIndex ) ;
400
+ _context . AddLinePragma ( linePragma ) ;
401
+
402
+ if ( ! _suppressLineDefaultAndHidden )
403
+ {
404
+ writer
405
+ . WriteLine ( "#line default" )
406
+ . WriteLine ( "#line hidden" ) ;
407
+ }
408
+
409
+ if ( ! _context . Options . SuppressNullabilityEnforcement )
410
+ {
411
+ writer . WriteLine ( "#nullable disable" ) ;
412
+ }
413
+
414
+ writer . CurrentIndent = _startIndent ;
276
415
}
277
416
}
278
417
}
0 commit comments