Skip to content

Commit 1660228

Browse files
committed
AvaloniaPreviewerSessionController: small refactoring, document the changes
1 parent 5abe894 commit 1660228

File tree

2 files changed

+33
-36
lines changed

2 files changed

+33
-36
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ When considering version compatibility (and thus incrementing the major version)
88

99
## [Unreleased] (1.9.0)
1010
### Added
11+
- Previewer will now restart automatically in case of execution errors. Thanks to @SuperJMN!
1112
- New C# file templates: **Avalonia Converter**, **Avalonia Multi Converter**. Thanks to @bugrakurnaz!
1213

1314
## [1.8.0] - 2025-11-16

src/rider/main/kotlin/me/fornever/avaloniarider/previewer/AvaloniaPreviewerSessionController.kt

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package me.fornever.avaloniarider.previewer
22

33
import com.intellij.execution.ui.ConsoleView
44
import com.intellij.openapi.application.EDT
5+
import com.intellij.openapi.application.readAction
56
import com.intellij.openapi.diagnostic.Logger
67
import com.intellij.openapi.diagnostic.debug
78
import com.intellij.openapi.editor.Document
@@ -11,6 +12,7 @@ import com.intellij.openapi.vfs.VirtualFile
1112
import com.intellij.platform.backend.workspace.WorkspaceModel
1213
import com.intellij.ui.scale.JBUIScale
1314
import com.intellij.util.application
15+
import com.intellij.workspaceModel.ide.toPath
1416
import com.jetbrains.rd.util.lifetime.Lifetime
1517
import com.jetbrains.rd.util.lifetime.LifetimeDefinition
1618
import com.jetbrains.rd.util.lifetime.SequentialLifetimes
@@ -22,21 +24,15 @@ import com.jetbrains.rd.util.throttleLast
2224
import com.jetbrains.rider.build.BuildHost
2325
import com.jetbrains.rider.model.riderSolutionLifecycle
2426
import com.jetbrains.rider.projectView.solution
25-
import com.intellij.workspaceModel.ide.toPath
2627
import com.jetbrains.rider.projectView.workspace.ProjectModelEntity
2728
import com.jetbrains.rider.projectView.workspace.containingProjectEntity
2829
import com.jetbrains.rider.projectView.workspace.getProjectModelEntities
2930
import com.jetbrains.rider.ui.SwingScheduler
3031
import com.jetbrains.rider.ui.components.utils.documentChanged
31-
import kotlinx.coroutines.CancellationException
32-
import kotlinx.coroutines.CompletableDeferred
33-
import kotlinx.coroutines.Dispatchers
34-
import kotlinx.coroutines.Job
32+
import kotlinx.coroutines.*
3533
import kotlinx.coroutines.channels.BufferOverflow
36-
import kotlinx.coroutines.delay
3734
import kotlinx.coroutines.flow.MutableSharedFlow
3835
import kotlinx.coroutines.flow.collectLatest
39-
import kotlinx.coroutines.withContext
4036
import me.fornever.avaloniarider.AvaloniaRiderBundle
4137
import me.fornever.avaloniarider.controlmessages.AvaloniaInputEventMessage
4238
import me.fornever.avaloniarider.controlmessages.FrameMessage
@@ -56,6 +52,8 @@ import java.net.SocketException
5652
import java.nio.file.Files
5753
import java.nio.file.Path
5854
import java.time.Duration
55+
import kotlin.coroutines.resume
56+
import kotlin.coroutines.resumeWithException
5957

6058
/**
6159
* The sources on this class are thread-free. Make sure to schedule them onto the proper threads if necessary.
@@ -182,38 +180,36 @@ class AvaloniaPreviewerSessionController(
182180
}
183181
}
184182

185-
private suspend fun getProjectContainingFile(virtualFile: VirtualFile): ProjectModelEntity? {
186-
application.assertIsDispatchThread()
187-
188-
val result = CompletableDeferred<ProjectModelEntity?>()
183+
private suspend fun getProjectContainingFile(virtualFile: VirtualFile): ProjectModelEntity? =
184+
suspendCancellableCoroutine { cont ->
185+
Lifetime.using { lt ->
186+
application.assertIsDispatchThread()
187+
188+
project.solution.riderSolutionLifecycle.isProjectModelReady.adviseUntil(lt) { isReady ->
189+
if (!isReady) return@adviseUntil false
190+
try {
191+
logger.debug { "Project model view synchronized" }
192+
val projectModelEntities = workspaceModel.getProjectModelEntities(virtualFile, project)
193+
logger.debug {
194+
"Project model nodes for file $xamlFile: " + projectModelEntities.joinToString(", ")
195+
}
196+
val containingProject =
197+
projectModelEntities.firstNotNullOfOrNull { it.containingProjectEntity() }
198+
if (containingProject != null) {
199+
cont.resume(containingProject)
200+
} else {
201+
logger.warn("Workspace model doesn't contain project entity for $virtualFile")
202+
cont.resume(null)
203+
}
204+
} catch (t: Throwable) {
205+
cont.resumeWithException(t)
206+
}
189207

190-
project.solution.riderSolutionLifecycle.isProjectModelReady.adviseUntil(controllerLifetime) { isReady ->
191-
if (!isReady) return@adviseUntil false
192-
try {
193-
logger.debug { "Project model view synchronized" }
194-
val projectModelEntities = workspaceModel.getProjectModelEntities(virtualFile, project)
195-
logger.debug {
196-
"Project model nodes for file $xamlFile: " + projectModelEntities.joinToString(", ")
197-
}
198-
val containingProject = projectModelEntities.asSequence()
199-
.mapNotNull { it.containingProjectEntity() }
200-
.firstOrNull()
201-
if (containingProject != null) {
202-
result.complete(containingProject)
203-
} else {
204-
logger.warn("Workspace model doesn't contain project entity for $virtualFile")
205-
result.complete(null)
208+
return@adviseUntil true
206209
}
207-
} catch (t: Throwable) {
208-
result.completeExceptionally(t)
209210
}
210-
211-
return@adviseUntil true
212211
}
213212

214-
return result.await()
215-
}
216-
217213
private fun createSession(
218214
lifetime: Lifetime,
219215
socket: ServerSocket,
@@ -240,7 +236,7 @@ class AvaloniaPreviewerSessionController(
240236

241237
suspend fun dispatchXamlUpdate() {
242238
while (lifetime.isAlive) {
243-
val (text, projectRelativePath) = application.runReadAction<Pair<String, String?>> {
239+
val (text, projectRelativePath) = readAction {
244240
document.text to computeDocumentPathInProject(projectFilePathProperty.valueOrNull)
245241
}
246242
val effectivePath = projectRelativePath ?: lastKnownProjectRelativePath
@@ -249,7 +245,7 @@ class AvaloniaPreviewerSessionController(
249245
if (lastKnownProjectRelativePath == null) {
250246
logger.warn(message)
251247
} else {
252-
logger.debug { message }
248+
logger.info(message)
253249
}
254250
inFlightUpdate.value = false
255251
delay(projectPathRetryDelay.toMillis())

0 commit comments

Comments
 (0)