@@ -15,7 +15,6 @@ internal sealed class CompilationHandler : IDisposable
15
15
{
16
16
public readonly IncrementalMSBuildWorkspace Workspace ;
17
17
public readonly EnvironmentOptions EnvironmentOptions ;
18
- private readonly GlobalOptions _options ;
19
18
private readonly IReporter _reporter ;
20
19
private readonly WatchHotReloadService _hotReloadService ;
21
20
@@ -41,11 +40,10 @@ internal sealed class CompilationHandler : IDisposable
41
40
42
41
private bool _isDisposed ;
43
42
44
- public CompilationHandler ( IReporter reporter , EnvironmentOptions environmentOptions , GlobalOptions options , CancellationToken shutdownCancellationToken )
43
+ public CompilationHandler ( IReporter reporter , EnvironmentOptions environmentOptions , CancellationToken shutdownCancellationToken )
45
44
{
46
45
_reporter = reporter ;
47
46
EnvironmentOptions = environmentOptions ;
48
- _options = options ;
49
47
Workspace = new IncrementalMSBuildWorkspace ( reporter ) ;
50
48
_hotReloadService = new WatchHotReloadService ( Workspace . CurrentSolution . Services , ( ) => ValueTask . FromResult ( GetAggregateCapabilities ( ) ) ) ;
51
49
_shutdownCancellationToken = shutdownCancellationToken ;
@@ -265,6 +263,7 @@ private static void PrepareCompilations(Solution solution, string projectPath, C
265
263
}
266
264
267
265
public async ValueTask < ( ImmutableDictionary < ProjectId , string > projectsToRebuild , ImmutableArray < RunningProject > terminatedProjects ) > HandleManagedCodeChangesAsync (
266
+ bool autoRestart ,
268
267
Func < IEnumerable < string > , CancellationToken , Task > restartPrompt ,
269
268
CancellationToken cancellationToken )
270
269
{
@@ -275,8 +274,8 @@ private static void PrepareCompilations(Solution solution, string projectPath, C
275
274
( from project in currentSolution . Projects
276
275
let runningProject = GetCorrespondingRunningProject ( project , runningProjects )
277
276
where runningProject != null
278
- let autoRestart = _options . NonInteractive || runningProject . ProjectNode . IsAutoRestartEnabled ( )
279
- select ( project . Id , info : new WatchHotReloadService . RunningProjectInfo ( ) { RestartWhenChangesHaveNoEffect = autoRestart } ) )
277
+ let autoRestartProject = autoRestart || runningProject . ProjectNode . IsAutoRestartEnabled ( )
278
+ select ( project . Id , info : new WatchHotReloadService . RunningProjectInfo ( ) { RestartWhenChangesHaveNoEffect = autoRestartProject } ) )
280
279
. ToImmutableDictionary ( e => e . Id , e => e . info ) ;
281
280
282
281
var updates = await _hotReloadService . GetUpdatesAsync ( currentSolution , runningProjectInfos , cancellationToken ) ;
@@ -290,41 +289,43 @@ private static void PrepareCompilations(Solution solution, string projectPath, C
290
289
return ( ImmutableDictionary < ProjectId , string > . Empty , [ ] ) ;
291
290
}
292
291
293
- ImmutableDictionary < string , ImmutableArray < RunningProject > > projectsToUpdate ;
294
- lock ( _runningProjectsAndUpdatesGuard )
292
+ if ( updates . ProjectUpdates . Any ( ) )
295
293
{
296
- // Adding the updates makes sure that all new processes receive them before they are added to running processes.
297
- _previousUpdates = _previousUpdates . AddRange ( updates . ProjectUpdates ) ;
294
+ ImmutableDictionary < string , ImmutableArray < RunningProject > > projectsToUpdate ;
295
+ lock ( _runningProjectsAndUpdatesGuard )
296
+ {
297
+ // Adding the updates makes sure that all new processes receive them before they are added to running processes.
298
+ _previousUpdates = _previousUpdates . AddRange ( updates . ProjectUpdates ) ;
298
299
299
- // Capture the set of processes that do not have the currently calculated deltas yet.
300
- projectsToUpdate = _runningProjects ;
301
- }
300
+ // Capture the set of processes that do not have the currently calculated deltas yet.
301
+ projectsToUpdate = _runningProjects ;
302
+ }
302
303
303
- // Apply changes to all running projects, even if they do not have a static project dependency on any project that changed.
304
- // The process may load any of the binaries using MEF or some other runtime dependency loader.
304
+ // Apply changes to all running projects, even if they do not have a static project dependency on any project that changed.
305
+ // The process may load any of the binaries using MEF or some other runtime dependency loader.
305
306
306
- await ForEachProjectAsync ( projectsToUpdate , async ( runningProject , cancellationToken ) =>
307
- {
308
- try
307
+ await ForEachProjectAsync ( projectsToUpdate , async ( runningProject , cancellationToken ) =>
309
308
{
310
- using var processCommunicationCancellationSource = CancellationTokenSource . CreateLinkedTokenSource ( runningProject . ProcessExitedSource . Token , cancellationToken ) ;
311
- var applySucceded = await runningProject . DeltaApplier . ApplyManagedCodeUpdates ( updates . ProjectUpdates , processCommunicationCancellationSource . Token ) != ApplyStatus . Failed ;
312
- if ( applySucceded )
309
+ try
313
310
{
314
- runningProject . Reporter . Report ( MessageDescriptor . HotReloadSucceeded ) ;
315
- if ( runningProject . BrowserRefreshServer is { } server )
311
+ using var processCommunicationCancellationSource = CancellationTokenSource . CreateLinkedTokenSource ( runningProject . ProcessExitedSource . Token , cancellationToken ) ;
312
+ var applySucceded = await runningProject . DeltaApplier . ApplyManagedCodeUpdates ( updates . ProjectUpdates , processCommunicationCancellationSource . Token ) != ApplyStatus . Failed ;
313
+ if ( applySucceded )
316
314
{
317
- runningProject . Reporter . Verbose ( "Refreshing browser." ) ;
318
- await server . RefreshBrowserAsync ( cancellationToken ) ;
315
+ runningProject . Reporter . Report ( MessageDescriptor . HotReloadSucceeded ) ;
316
+ if ( runningProject . BrowserRefreshServer is { } server )
317
+ {
318
+ runningProject . Reporter . Verbose ( "Refreshing browser." ) ;
319
+ await server . RefreshBrowserAsync ( cancellationToken ) ;
320
+ }
319
321
}
320
322
}
321
- }
322
- catch ( OperationCanceledException ) when ( runningProject . ProcessExitedSource . Token . IsCancellationRequested && ! cancellationToken . IsCancellationRequested )
323
- {
324
- runningProject . Reporter . Verbose ( "Hot reload canceled because the process exited." , emoji : "🔥" ) ;
325
- }
326
- } , cancellationToken ) ;
327
-
323
+ catch ( OperationCanceledException ) when ( runningProject . ProcessExitedSource . Token . IsCancellationRequested && ! cancellationToken . IsCancellationRequested )
324
+ {
325
+ runningProject . Reporter . Verbose ( "Hot reload canceled because the process exited." , emoji : "🔥" ) ;
326
+ }
327
+ } , cancellationToken ) ;
328
+ }
328
329
329
330
if ( updates . ProjectsToRestart . IsEmpty )
330
331
{
@@ -430,11 +431,15 @@ void ReportRudeEdits()
430
431
// Rude edits in projects that caused restart of a project that can be restarted automatically
431
432
// will be reported only as verbose output.
432
433
var projectsRestartedDueToRudeEdits = updates . ProjectsToRestart
433
- . Where ( e => runningProjectInfos . TryGetValue ( e . Key , out var info ) && info . RestartWhenChangesHaveNoEffect )
434
+ . Where ( e => IsAutoRestartEnabled ( e . Key ) )
434
435
. SelectMany ( e => e . Value )
435
436
. ToHashSet ( ) ;
436
437
437
- var projectsRebuiltDueToRudeEdits = updates . ProjectsToRebuild . ToHashSet ( ) ;
438
+ // Project with rude edit that doesn't impact running project is only listed in ProjectsToRebuild.
439
+ // Such projects are always auto-rebuilt whether or not there is any project to be restarted that needs a confirmation.
440
+ var projectsRebuiltDueToRudeEdits = updates . ProjectsToRebuild
441
+ . Where ( p => ! updates . ProjectsToRestart . ContainsKey ( p ) )
442
+ . ToHashSet ( ) ;
438
443
439
444
foreach ( var ( projectId , diagnostics ) in updates . RudeEdits )
440
445
{
@@ -451,6 +456,9 @@ void ReportRudeEdits()
451
456
}
452
457
}
453
458
459
+ bool IsAutoRestartEnabled ( ProjectId id )
460
+ => runningProjectInfos . TryGetValue ( id , out var info ) && info . RestartWhenChangesHaveNoEffect ;
461
+
454
462
void ReportDiagnostic ( Diagnostic diagnostic , MessageDescriptor descriptor , string prefix = "" )
455
463
{
456
464
var display = CSharpDiagnosticFormatter . Instance . Format ( diagnostic ) ;
0 commit comments