Hot reload as a third launch mode, rewritten from dotnet-hot-reload

dotnet watch run with the startup project, configuration, platform and
per-project launch options from the status bar. The debugger is no
longer attached automatically: attach on demand, one notification with
Re-attach when the watcher replaces the process. Rude edits follow a
setting (restart / ask / warn). Warns before starting under an optimised
configuration, which SDK 10's dotnet watch cannot hot reload. Solution
build runs first so the Editor's post-build step finds the Builder.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0169iPWwKHZoBTNN9qwXiwqk
This commit is contained in:
max
2026-09-08 13:47:37 +02:00
co-authored by Claude Fable 5.1
parent 63de8a31f6
commit 0cae24a1f0
10 changed files with 1164 additions and 9 deletions
+56 -4
View File
@@ -1,11 +1,10 @@
# .NET Solution Launcher
Startup project and solution configuration in the status bar, with build and debug that
actually use them. Built for [DotRush](https://github.com/JaneySprings/DotRush), next to
the `.NET Hot Reload` extension in this repo.
Startup project and solution configuration in the status bar, with build, debug, run and
hot reload that actually use them. Built for [DotRush](https://github.com/JaneySprings/DotRush).
```
$(project) MyGame.Editor $(settings-gear) Test | x64 $(debug-alt)
$(project) MyGame.Editor $(settings-gear) Test | x64 $(debug-alt) $(flame) Hot Reload
```
- The **project item** shows which `.csproj` is the startup project, and picks another one
@@ -13,6 +12,7 @@ $(project) MyGame.Editor $(settings-gear) Test | x64 $(debug-alt)
- The **configuration item** shows the *solution* configuration — `Debug | x64`,
`Test | x64`, `Release | Any CPU` — exactly as `MyGame.sln` lists them.
- The **debug button** builds with that configuration and launches the startup project.
- The **flame** starts it under `dotnet watch` with hot reload instead.
## Why, when DotRush already has a status bar item
@@ -93,6 +93,54 @@ Builder and Editor want different arguments, so these are layered, most specific
The same layering applies to F5 through the launch.json entry: its `args` stay empty in
the file and are filled in at launch time.
## Hot reload
The third way to start the startup project, next to Debug and Run, and a rewrite of the
earlier `dotnet-hot-reload` extension now that the selection exists to build on:
```
dotnet watch run --project MyGame.Editor.csproj -c Debug --property:Platform=x64 -- <args>
```
Same project, configuration, platform, arguments, environment and working directory as
F5. It runs in an integrated terminal named after the project, and the status bar item
next to the debug button follows the watcher's output: *watching*, *applied*, *failed*,
*restart needed*. Save a file and the change is applied; the flame in the terminal's
title is the same session.
| Action | How |
| --- | --- |
| Start | The `$(flame) Hot Reload` status bar item, *.NET Solution: Run Startup Project with Hot Reload*, or `Ctrl+Alt+F5` |
| Apply, restart, attach, stop | Click the status bar item while it runs — one menu for all of them |
| Restart the application | Also `Ctrl+R` inside the watch terminal |
**The debugger is not attached by default.** That is the biggest change from the old
extension, and deliberate. `dotnet watch` replaces the application process on every
rude edit, restart or crash, and each of those ends an attached debug session; keeping a
debugger attached across that meant guessing whether an ended session was a stop or a
swap, racing the outgoing process, and giving up on crash loops. Now *Attach Debugger*
finds the application below the watcher (by assembly name, so MSBuild is never picked)
and attaches when you ask. If the process is later replaced while the watcher still
runs, one notification says so and offers to re-attach. While attached, the flame and
restart buttons also appear in the debug toolbar.
**Rude edits** — changes hot reload cannot apply — follow `dotnetSolution.hotReload.rudeEdit`:
| Value | Behaviour |
| --- | --- |
| `restart` (default) | dotnet watch restarts the application on its own |
| `ask` | A notification offers *Restart* / *Keep running*; the answer goes to dotnet watch's console question |
| `warn` | Keeps the old code running and shows a warning with a *Restart* button |
**Optimised builds cannot hot reload.** SDK 10's `dotnet watch` refuses when `Optimize`
is true and restarts on every change instead. Test and Release set it here, so starting
hot reload under those asks whether to switch to Debug first.
**Solution build first.** `dotnet watch` only builds the project it runs. With
`dotnetSolution.hotReload.buildSolutionFirst` (default on) the normal solution build runs
before the watcher starts, so the Editor's post-build step finds the Builder even on a
clean checkout; the watcher's own build is then incremental.
## Usage
| Action | How |
@@ -102,6 +150,7 @@ the file and are filled in at launch time.
| Build / Rebuild / Clean | *.NET Solution: Build* etc., or the `dotnet-solution` tasks. `Ctrl+Shift+B` until a launch.json entry exists, after that VS Code's default build task |
| Publish / Test | *.NET Solution: Publish Startup Project*, *.NET Solution: Run Tests* |
| Debug | The `$(debug-alt)` button, *.NET Solution: Debug Startup Project*, or F5 |
| Hot reload | The `$(flame)` item, or `Ctrl+Alt+F5`. See above |
| Run without debugging | *.NET Solution: Run Startup Project (without debugging)*, or `Ctrl+F5` |
| Several `.sln` files | *.NET Solution: Select Solution*, or `dotnetSolution.solution` |
@@ -157,6 +206,9 @@ The same entry is offered dynamically in the *Run and Debug* dropdown even witho
| `dotnetSolution.publish.runtime` / `.args` | `""` / `[]` | `-r` and extra arguments for publish |
| `dotnetSolution.test.args` | `[]` | Extra arguments for test |
| `dotnetSolution.showProblemsOnFailure` | `true` | Open Problems when a task fails |
| `dotnetSolution.hotReload.rudeEdit` | `restart` | `restart`, `ask` or `warn` |
| `dotnetSolution.hotReload.buildSolutionFirst` | `true` | Solution build before `dotnet watch` |
| `dotnetSolution.hotReload.watchArgs` | `[]` | Extra arguments for `dotnet watch` itself |
| `dotnetSolution.debugType` | `coreclr` | |
| `dotnetSolution.syncDotRush` | `true` | Push the startup project to DotRush and follow its changes |
| `dotnetSolution.syncDotRushWorkspaceProperties` | `false` | Write `Configuration=…;Platform=…` into `dotrush.roslyn.workspaceProperties` so IntelliSense sees the same `DefineConstants`. Off because DotRush reloads its workspace on every change |