diff --git a/platform/editor/backend/intellij.platform.editor.backend.iml b/platform/editor/backend/intellij.platform.editor.backend.iml
index ae9ca1c16b1b..a85fc253bdd9 100644
--- a/platform/editor/backend/intellij.platform.editor.backend.iml
+++ b/platform/editor/backend/intellij.platform.editor.backend.iml
@@ -17,5 +17,6 @@
+
\ No newline at end of file
diff --git a/platform/editor/backend/src/BackendEditorState.kt b/platform/editor/backend/src/BackendEditorState.kt
index a868c00f65aa..96ea86ed56dd 100644
--- a/platform/editor/backend/src/BackendEditorState.kt
+++ b/platform/editor/backend/src/BackendEditorState.kt
@@ -4,14 +4,15 @@ package com.intellij.platform.editor.backend
import com.intellij.codeWithMe.clientId
import com.intellij.openapi.application.isRhizomeAdEnabled
import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.editor.impl.ad.AdDocumentEntity
import com.intellij.openapi.editor.impl.editorId
import com.intellij.platform.editor.EditorEntity
import com.intellij.platform.kernel.KernelService
import com.intellij.platform.kernel.util.kernelCoroutineContext
+import com.intellij.platform.pasta.common.DocumentEntity
import com.intellij.platform.util.coroutines.childScope
import fleet.kernel.change
import fleet.kernel.shared
+import fleet.util.UID
import kotlinx.coroutines.*
internal class BackendEditorState(
@@ -32,7 +33,7 @@ internal class BackendEditorState(
val clientId = requireNotNull(currentCoroutineContext().clientId())
val editorEntity = change {
shared {
- val document = AdDocumentEntity.fromString(editor.document.text, editor.document.modificationStamp)
+ val document = DocumentEntity.fromText(UID.random(), editor.document.text)
EditorEntity.new {
it[EditorEntity.idAttr] = editor.editorId()
it[EditorEntity.clientIdAttr] = clientId
diff --git a/platform/editor/shared/src/EditorEntity.kt b/platform/editor/shared/src/EditorEntity.kt
index 86baa0c99029..9964e5874177 100644
--- a/platform/editor/shared/src/EditorEntity.kt
+++ b/platform/editor/shared/src/EditorEntity.kt
@@ -3,7 +3,7 @@ package com.intellij.platform.editor
import com.intellij.codeWithMe.ClientId
import com.intellij.openapi.editor.impl.EditorId
-import com.intellij.openapi.editor.impl.ad.AdDocumentEntity
+import com.intellij.platform.pasta.common.DocumentEntity
import com.jetbrains.rhizomedb.EID
import com.jetbrains.rhizomedb.Entity
import com.jetbrains.rhizomedb.Indexing
@@ -16,7 +16,7 @@ import org.jetbrains.annotations.ApiStatus.Internal
@Internal
data class EditorEntity(override val eid: EID) : Entity {
- val document: AdDocumentEntity by documentAttr
+ val document: DocumentEntity by documentAttr
val id: EditorId by idAttr
val clientId: ClientId by clientIdAttr
@@ -27,7 +27,7 @@ data class EditorEntity(override val eid: EID) : Entity {
) {
val idAttr: Required = requiredValue("id", EditorId.serializer(), Indexing.UNIQUE)
- val documentAttr: Required = requiredRef("document", RefFlags.CASCADE_DELETE_BY)
+ val documentAttr: Required = requiredRef("document", RefFlags.CASCADE_DELETE_BY)
val clientIdAttr: Required = requiredValue("clientId", ClientIdSerializer)
}
}
diff --git a/platform/editor/shared/src/EditorEntityTypeProvider.kt b/platform/editor/shared/src/EditorEntityTypeProvider.kt
index f0968f06034a..df1037b26780 100644
--- a/platform/editor/shared/src/EditorEntityTypeProvider.kt
+++ b/platform/editor/shared/src/EditorEntityTypeProvider.kt
@@ -2,10 +2,9 @@
package com.intellij.platform.editor
import com.intellij.openapi.application.isRhizomeAdEnabled
-import com.intellij.openapi.editor.impl.ad.AdDocumentEntity
+import com.intellij.platform.kernel.EntityTypeProvider
import com.intellij.platform.pasta.common.DocumentEntity
import com.intellij.platform.pasta.common.EditLogEntity
-import com.intellij.platform.kernel.EntityTypeProvider
import com.jetbrains.rhizomedb.EntityType
internal class EditorEntityTypeProvider : EntityTypeProvider {
@@ -13,7 +12,6 @@ internal class EditorEntityTypeProvider : EntityTypeProvider {
override fun entityTypes(): List> {
if (!isRhizomeAdEnabled) return emptyList()
return listOf(
- AdDocumentEntity,
EditorEntity,
DocumentEntity,
EditLogEntity,
diff --git a/platform/kernel/pasta/src/common/DocumentEntity.kt b/platform/kernel/pasta/src/common/DocumentEntity.kt
index 034fe260e71b..c5d3ddbb3d09 100644
--- a/platform/kernel/pasta/src/common/DocumentEntity.kt
+++ b/platform/kernel/pasta/src/common/DocumentEntity.kt
@@ -40,6 +40,16 @@ class DocumentEntity(override val eid: EID) : Entity {
val WritableAttr: Required = requiredValue("writable", Boolean.serializer())
val EditLogAttr: Required = requiredRef("editLogEntity", RefFlags.UNIQUE)
val SharedAnchorStorageAttr: Required = requiredValue("sharedAnchorStorage", AnchorStorage.serializer())
+
+ fun fromText(uid: UID, text: CharSequence): DocumentEntity = requireChangeScope {
+ DocumentEntity.new {
+ it[Durable.Id] = uid
+ it[TextAttr] = Text.fromString(text.toString())
+ it[WritableAttr] = true
+ it[EditLogAttr] = createEmptyEditLog()
+ it[SharedAnchorStorageAttr] = AnchorStorage.empty()
+ }
+ }
}
val timestamp: Long
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/AdTheManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/AdTheManager.java
deleted file mode 100644
index 34d8078fbd34..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/AdTheManager.java
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.openapi.editor.ex;
-
-import com.intellij.openapi.editor.impl.ad.AdTheManagerImpl;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.ApiStatus;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-@ApiStatus.Experimental
-@ApiStatus.Internal
-public interface AdTheManager {
-
- static @NotNull AdTheManager getInstance(@NotNull Project project) {
- return project.getService(AdTheManagerImpl.class);
- }
-
- @Nullable EditorModel createEditorModel(@NotNull EditorEx editor);
-}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorFactoryImpl.kt b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorFactoryImpl.kt
index 988107ef6996..884aaaf6c6f4 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorFactoryImpl.kt
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorFactoryImpl.kt
@@ -21,7 +21,7 @@ import com.intellij.openapi.editor.event.EditorFactoryListener
import com.intellij.openapi.editor.ex.EditorEx
import com.intellij.openapi.editor.highlighter.EditorHighlighter
import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory
-import com.intellij.openapi.editor.impl.ad.v2.AdTheManagerV2
+import com.intellij.openapi.editor.impl.ad.AdTheManager
import com.intellij.openapi.editor.impl.event.EditorEventMulticasterImpl
import com.intellij.openapi.editor.impl.view.EditorPainter
import com.intellij.openapi.extensions.ExtensionPointName
@@ -209,7 +209,7 @@ class EditorFactoryImpl(coroutineScope: CoroutineScope?) : EditorFactory() {
highlighter: EditorHighlighter?,
afterCreation: ((EditorImpl) -> Unit)?,
): EditorImpl {
- AdTheManagerV2.getInstance().bindLocalDocEntity(document)
+ AdTheManager.getInstance().bindLocalDocEntity(document)
val editor = EditorImpl(document, isViewer, project, kind, file, highlighter)
editor.putEditorId()
// must be _before_ event firing
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
index cb0543e3733b..57136c06e5df 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
@@ -37,7 +37,7 @@ import com.intellij.openapi.editor.ex.util.EditorUtil;
import com.intellij.openapi.editor.ex.util.EmptyEditorHighlighter;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.editor.highlighter.HighlighterClient;
-import com.intellij.openapi.editor.impl.ad.v2.AdTheManagerV2;
+import com.intellij.openapi.editor.impl.ad.AdTheManager;
import com.intellij.openapi.editor.impl.event.MarkupModelListener;
import com.intellij.openapi.editor.impl.stickyLines.StickyLinesManager;
import com.intellij.openapi.editor.impl.stickyLines.StickyLinesModel;
@@ -342,7 +342,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
final EditorView myView;
final @Nullable EditorView myAdView;
- private static final boolean AD_V2 = Registry.is("ijpl.rhizome.ad.v2.enabled", false);
private boolean myCharKeyPressed;
private boolean myNeedToSelectPreviousChar;
@@ -479,27 +478,22 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
myEditorModel = new EditorModelImpl(this);
- if (AD_V2) {
- DocumentEx adDocumentV2 = AdTheManagerV2.getInstance().getAdDocument(myDocument);
- myAdEditorModel = adDocumentV2 == null ? null : new EditorModel() {
- @Override public DocumentEx getDocument() { return adDocumentV2; }
- @Override public MarkupModelEx getEditorMarkupModel() { return myMarkupModel; }
- @Override public MarkupModelEx getDocumentMarkupModel() { return myEditorFilteringMarkupModel; }
- @Override public EditorHighlighter getHighlighter() { return myHighlighter; }
- @Override public InlayModelEx getInlayModel() { return myInlayModel; }
- @Override public FoldingModelEx getFoldingModel() { return myFoldingModel; }
- @Override public SoftWrapModelEx getSoftWrapModel() { return mySoftWrapModel; }
- @Override public CaretModel getCaretModel() { return myCaretModel; }
- @Override public SelectionModel getSelectionModel() { return mySelectionModel; }
- @Override public ScrollingModel getScrollingModel() { return myScrollingModel; }
- @Override public FocusModeModel getFocusModel() { return myFocusModeModel; }
- @Override public boolean isAd() { return true; }
- @Override public void dispose() { AdTheManagerV2.getInstance().releaseDocEntity(myDocument); }
- };
- }
- else {
- myAdEditorModel = project == null ? null : AdTheManager.getInstance(project).createEditorModel(this);
- }
+ DocumentEx adDocument = AdTheManager.getInstance().getAdDocument(myDocument);
+ myAdEditorModel = adDocument == null ? null : new EditorModel() {
+ @Override public DocumentEx getDocument() { return adDocument; }
+ @Override public MarkupModelEx getEditorMarkupModel() { return myMarkupModel; }
+ @Override public MarkupModelEx getDocumentMarkupModel() { return myEditorFilteringMarkupModel; }
+ @Override public EditorHighlighter getHighlighter() { return myHighlighter; }
+ @Override public InlayModelEx getInlayModel() { return myInlayModel; }
+ @Override public FoldingModelEx getFoldingModel() { return myFoldingModel; }
+ @Override public SoftWrapModelEx getSoftWrapModel() { return mySoftWrapModel; }
+ @Override public CaretModel getCaretModel() { return myCaretModel; }
+ @Override public SelectionModel getSelectionModel() { return mySelectionModel; }
+ @Override public ScrollingModel getScrollingModel() { return myScrollingModel; }
+ @Override public FocusModeModel getFocusModel() { return myFocusModeModel; }
+ @Override public boolean isAd() { return true; }
+ @Override public void dispose() { AdTheManager.getInstance().releaseDocEntity(myDocument); }
+ };
myView = new EditorView(this, myEditorModel);
myAdView = myAdEditorModel == null ? null : new EditorView(this, myAdEditorModel);
@@ -532,8 +526,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
addListeners();
- if (AD_V2 && myAdEditorModel != null) {
- AdTheManagerV2.getInstance().bindEditor(this);
+ if (myAdEditorModel != null) {
+ AdTheManager.getInstance().bindEditor(this);
}
}
@@ -1188,9 +1182,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
Disposer.dispose(myView);
if (myAdView != null) {
Disposer.dispose(myAdView);
- if (AD_V2) {
- Disposer.dispose(myAdEditorModel);
- }
+ Disposer.dispose(myAdEditorModel);
}
clearCaretThread();
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdDocument.kt b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdDocument.kt
index b39122b8755d..2e4fc1fee4f1 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdDocument.kt
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdDocument.kt
@@ -1,11 +1,6 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.editor.impl.ad
-import andel.editor.RangeMarkerId
-import andel.intervals.Interval
-import andel.operation.Operation
-import andel.operation.captureOperation
-import andel.operation.rebase
import andel.text.*
import com.intellij.openapi.Disposable
import com.intellij.openapi.editor.RangeMarker
@@ -14,65 +9,16 @@ import com.intellij.openapi.editor.ex.DocumentEx
import com.intellij.openapi.editor.ex.EditReadOnlyListener
import com.intellij.openapi.editor.ex.LineIterator
import com.intellij.openapi.editor.ex.RangeMarkerEx
+import com.intellij.platform.pasta.common.DocumentEntity
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.TextRange
import com.intellij.util.Processor
-import com.intellij.util.concurrency.ThreadingAssertions
-import com.jetbrains.rhizomedb.ChangeScope
-import com.jetbrains.rhizomedb.DbContext
-import com.jetbrains.rhizomedb.asOf
-import com.jetbrains.rhizomedb.requireChangeScope
-import fleet.util.UID
import org.jetbrains.annotations.ApiStatus.Experimental
import java.beans.PropertyChangeListener
import java.util.*
@Experimental
-internal class AdDocument(
- private val name: String,
- private val entity: AdDocumentEntity,
-) : DocumentEx {
-
- internal fun replaceString(startOffset: Int, endOffset: Int, chars: CharSequence, modStamp: Long) {
- performTextOperation(modStamp) {
- textView().replaceOperation(startOffset, endOffset, chars.toString())
- }
- }
-
- internal fun queryRangeMarkers(startOffset: Long, endOffset: Long): Sequence> {
- return documentRead {
- entity.anchorStorage.intervals.query(startOffset, endOffset)
- }
- }
-
- internal fun addRangeMarkers(rangeIds: List, ranges: List) {
- documentChange {
- entity[AdDocumentEntity.AnchorStorageAttr] = entity.anchorStorage.batchUpdate(
- emptyList(),
- LongArray(0),
- rangeIds,
- ranges, // TODO: greedy
- )
- }
- }
-
- internal fun addRangeMarker(rangeId: RangeMarkerId, startOffset: Long, endOffset: Long) {
- documentChange {
- entity[AdDocumentEntity.AnchorStorageAttr] = entity.anchorStorage.addRangeMarker(
- rangeId,
- startOffset,
- endOffset,
- false, // TODO: greedy
- false,
- )
- }
- }
-
- internal fun removeRangeMarker(rangeId: RangeMarkerId) {
- documentChange {
- entity[AdDocumentEntity.AnchorStorageAttr] = entity.anchorStorage.removeRangeMarker(rangeId)
- }
- }
+internal class AdDocument(private val entity: DocumentEntity) : DocumentEx {
// region TEXT
@@ -214,7 +160,7 @@ internal class AdDocument(
override fun getModificationStamp(): Long {
return documentRead {
- entity.modStamp
+ entity.editLog.timestamp
}
}
@@ -361,50 +307,8 @@ internal class AdDocument(
return text().view()
}
- private fun textMutableView(): MutableTextView {
- return text().mutableView()
- }
-
private fun documentRead(block: () -> T): T {
- if (DbContext.threadLocal.get() != null) {
- return block()
- }
-
- ThreadingAssertions.assertBackgroundThread() // DB always exists w/i EDT
-
- // TODO: lastKnownOrPendingDb
- return asOf(ThreadLocalRhizomeDB.lastKnownDb()) {
- block()
- }
- }
-
- private fun documentChange(block: ChangeScope.() -> T): T {
- return requireChangeScope {
- block()
- }
- }
-
- private fun performTextOperation(modStamp: Long, operationLambda: ChangeScope.() -> Operation) {
- documentChange {
- val operationId = UID.random()
- val textBefore = entity.text
- val doc = entity.asAndelDocument()
- val versionedOperation = doc.captureOperation(operationLambda())
- val operation = versionedOperation.rebase(doc)
-
- val textAfter = textMutableView().apply { edit(operation) }.text()
- val editLogAfter = entity.editLog.append(operationId, operation).trim()
- val anchorStorageAfter = entity.anchorStorage.edit(textBefore, textAfter, operation)
-
- entity[AdDocumentEntity.TextAttr] = textAfter
- entity[AdDocumentEntity.ModStampAttr] = modStamp
- entity[AdDocumentEntity.EditLogAttr] = editLogAfter
- entity[AdDocumentEntity.AnchorStorageAttr] = anchorStorageAfter
- }
- }
-
- override fun toString(): String {
- return name
+ return block()
}
//endregion
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdDocumentEntity.kt b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdDocumentEntity.kt
deleted file mode 100644
index d88206bb6f3e..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdDocumentEntity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.openapi.editor.impl.ad
-
-import andel.editor.AnchorId
-import andel.editor.RangeMarkerId
-import andel.intervals.AnchorStorage
-import andel.operation.EditLog
-import andel.text.Text
-import andel.text.TextRange
-import com.jetbrains.rhizomedb.Attributes
-import com.jetbrains.rhizomedb.EID
-import com.jetbrains.rhizomedb.Entity
-import com.jetbrains.rhizomedb.requireChangeScope
-import fleet.kernel.DurableEntityType
-import kotlinx.serialization.builtins.serializer
-import org.jetbrains.annotations.ApiStatus.Experimental
-import org.jetbrains.annotations.ApiStatus.Internal
-
-private typealias Att = Attributes.Required
-
-@Experimental
-@Internal
-class AdDocumentEntity(override val eid: EID) : Entity {
- val text: Text by TextAttr
- val modStamp: Long by ModStampAttr
- val editLog: EditLog by EditLogAttr
- val anchorStorage: AnchorStorage by AnchorStorageAttr
-
- companion object : DurableEntityType(AdDocumentEntity::class, ::AdDocumentEntity) {
- val TextAttr: Att = requiredValue("text", Text.serializer())
- val ModStampAttr: Att = requiredValue("modStamp", Long.serializer())
- val EditLogAttr: Att = requiredValue("editLog", EditLog.serializer())
- val AnchorStorageAttr: Att = requiredValue("anchorStorage", AnchorStorage.serializer())
-
- fun fromString(text: String, modStamp: Long): AdDocumentEntity = requireChangeScope {
- AdDocumentEntity.new {
- it[TextAttr] = Text.fromString(text)
- it[ModStampAttr] = modStamp
- it[EditLogAttr] = EditLog.empty()
- it[AnchorStorageAttr] = AnchorStorage.empty()
- }
- }
- }
-
- fun asAndelDocument(): andel.editor.Document {
- return object : andel.editor.Document {
- override val text: Text get() = this@AdDocumentEntity.text
- override val timestamp: Long = editLog.timestamp
- override val edits: EditLog get() = editLog
- override fun resolveAnchor(anchorId: AnchorId): Long? = anchorStorage.resolveAnchor(anchorId)
- override fun resolveRangeMarker(markerId: RangeMarkerId): TextRange? = anchorStorage.resolveRangeMarker(markerId)
- }
- }
-
- override fun toString(): String {
- return "AdDocumentEntity(eid=$eid, modStamp=$modStamp, text=$text)"
- }
-}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdDocumentSynchronizer.kt b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdDocumentSynchronizer.kt
index bea985d58b6b..78d97426e490 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdDocumentSynchronizer.kt
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdDocumentSynchronizer.kt
@@ -1,62 +1,61 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.editor.impl.ad
-import com.intellij.openapi.Disposable
+import andel.operation.Operation
import com.intellij.openapi.editor.event.DocumentEvent
import com.intellij.openapi.editor.ex.PrioritizedDocumentListener
-import com.intellij.openapi.util.registry.Registry
+import com.intellij.platform.pasta.common.DocumentEntity
+import fleet.kernel.awaitCommitted
import fleet.kernel.change
-import fleet.kernel.shared
+import fleet.util.UID
+import fleet.util.openmap.OpenMap
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.async
+import kotlinx.coroutines.runBlocking
import org.jetbrains.annotations.ApiStatus.Experimental
@Experimental
-internal class AdDocumentSynchronizer(
- private val adDocument: AdDocument,
+internal data class AdDocumentSynchronizer(
+ private val documentId: Any, // RdDocumentId
+ private val entityId: UID,
private val coroutineScope: CoroutineScope,
- private val repaintLambda: suspend () -> Unit,
-) : PrioritizedDocumentListener, Disposable.Default {
+ private val entityDeferred: Deferred,
+): PrioritizedDocumentListener {
- override fun getPriority(): Int {
- return Integer.MIN_VALUE + 1
- }
+ override fun getPriority(): Int = Int.MIN_VALUE + 1
override fun documentChanged(event: DocumentEvent) {
- val realChars = event.document.immutableCharSequence
- coroutineScope.launch {
- if (isDebugMode()) {
- delay(500)
- }
- change {
- shared {
- adDocument.replaceString(
- startOffset = event.offset,
- endOffset = event.offset + event.oldLength,
- chars = event.newFragment,
- modStamp = event.document.modificationStamp,
- )
+ val entityChange = coroutineScope.async {
+ val operation = operation(event)
+ val entity = entityDeferred.await()
+ change { // it is a shared change
+ entity.mutate(this, OpenMap.empty()) {
+ edit(operation)
}
}
- val adChars = adDocument.immutableCharSequence
- if (realChars.hashCode() != adChars.hashCode()) {
- assert(realChars.toString() == adChars.toString()) {
- """
- AdDocument is out of sync, expected chars:
- $realChars
-
- but encountered:
- $adChars
- """.trimIndent()
- }
- }
- repaintLambda.invoke()
+ awaitCommitted()
}
+ // TODO: pumping events in runWithModalProgressBlocking ruins the models
+ //@Suppress("HardCodedStringLiteral")
+ //runWithModalProgressBlocking(
+ // ModalTaskOwner.guess(),
+ // "Shared document entity synchronization $entityId",
+ //) { entityChange.await() }
+ runBlocking { entityChange.await() }
+ ThreadLocalRhizomeDB.setThreadLocalDb(ThreadLocalRhizomeDB.lastKnownDb())
}
- private fun isDebugMode(): Boolean {
- return Registry.`is`("ijpl.rhizome.ad.debug.enabled", false)
+ private fun operation(event: DocumentEvent): Operation {
+ val oldFragment = event.oldFragment.toString()
+ val newFragment = event.newFragment.toString()
+ val lengthBefore = event.document.textLength - newFragment.length + oldFragment.length
+ return Operation.Companion.replaceAt(
+ offset = event.offset.toLong(),
+ oldText = oldFragment,
+ newText = newFragment,
+ totalLength = lengthBefore.toLong(),
+ )
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdInlayModel.kt b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdInlayModel.kt
deleted file mode 100644
index 3cba65d13cba..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdInlayModel.kt
+++ /dev/null
@@ -1,276 +0,0 @@
-// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.openapi.editor.impl.ad
-
-import andel.editor.RangeMarkerId
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.application.EDT
-import com.intellij.openapi.editor.*
-import com.intellij.openapi.editor.ex.InlayModelEx
-import com.intellij.openapi.editor.impl.InlayModelImpl
-import com.intellij.openapi.editor.markup.GutterIconRenderer
-import com.intellij.openapi.util.Key
-import com.jetbrains.rhizomedb.ChangeScope
-import fleet.kernel.change
-import fleet.kernel.shared
-import fleet.util.UID
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import org.jetbrains.annotations.ApiStatus.Experimental
-import java.awt.Point
-import java.awt.Rectangle
-import andel.text.TextRange as AndelTextRange
-
-
-@Experimental
-internal class AdInlayModel private constructor(
- private val adDocument: AdDocument,
- private val mapper: AdRangeMapper>,
- private val inlayModel: InlayModelImpl,
- private val coroutineScope: CoroutineScope,
- private val repaintLambda: suspend () -> Unit,
-) : InlayModelEx, Disposable {
-
- companion object {
- fun fromInlays(
- inlayModel: InlayModelImpl,
- adDocument: AdDocument,
- coroutineScope: CoroutineScope,
- repaintLambda: suspend () -> Unit,
- ): AdInlayModel {
- val mapper = AdRangeMapper>()
- val rangesIds = mutableListOf()
- val ranges = mutableListOf()
- for (inlay in inlayModel.getInlineElementsInRange(0, Integer.MAX_VALUE)) {
- val rangeId = UID.random()
- rangesIds.add(RangeMarkerId(rangeId))
- ranges.add(AndelTextRange(inlay.offset, inlay.offset))
- mapper.register(rangeId, inlay)
- }
- adDocument.addRangeMarkers(rangesIds, ranges)
- return AdInlayModel(adDocument, mapper, inlayModel, coroutineScope, repaintLambda)
- }
- }
-
- init {
- val listener = object : InlayModel.Listener {
- override fun onAdded(inlay: Inlay<*>) {
- onInlayUpdate {
- // TODO: incorrect offset -> ui offset
- val rangeId = UID.random()
- adDocument.addRangeMarker(
- RangeMarkerId(rangeId),
- inlay.offset.toLong(),
- inlay.offset.toLong(),
- )
- mapper.register(rangeId, inlay)
- }
- }
- override fun onRemoved(inlay: Inlay<*>) {
- onInlayUpdate {
- val rangeId = mapper.unregister(inlay)
- if (rangeId != null) {
- adDocument.removeRangeMarker(RangeMarkerId(rangeId))
- }
- }
- }
- }
- coroutineScope.launch(Dispatchers.EDT) {
- inlayModel.addListener(listener, this@AdInlayModel)
- }
- }
-
- private fun onInlayUpdate(body: ChangeScope.() -> Unit) {
- coroutineScope.launch {
- change {
- shared {
- body()
- }
- }
- repaintLambda.invoke()
- }
- }
-
- override fun getBlockElementsForVisualLine(visualLine: Int, above: Boolean): List?> {
- return emptyList()
- }
-
- override fun getAfterLineEndElementsForLogicalLine(logicalLine: Int): List?> {
- return emptyList()
- }
-
- override fun getInlineElementsInRange(startOffset: Int, endOffset: Int): List> {
- val inlays = mutableListOf>()
- for (interval in adDocument.queryRangeMarkers(startOffset.toLong(), endOffset.toLong())) {
- val inlay = mapper.resolveRange(interval.id)
- if (inlay != null) {
- val offset = interval.from.toInt()
- inlays.add(AdInlay(offset, inlay))
- }
- }
- return inlays
- }
-
- override fun getAfterLineEndElementsInRange(startOffset: Int, endOffset: Int): List?> {
- return emptyList()
- }
-
- override fun getBlockElementsInRange(startOffset: Int, endOffset: Int): List?> {
- return emptyList()
- }
-
- /**
- * FoldingModel
- * CaretModel
- * EditorImpl
- * SoftWrapModel
- * EditorSizeManager
- */
- override fun addListener(listener: InlayModel.Listener, disposable: Disposable) {
- }
-
- override fun isInBatchMode(): Boolean {
- return false
- }
-
- override fun getHeightOfBlockElementsBeforeVisualLine(visualLine: Int, startOffset: Int, prevFoldRegionIndex: Int): Int {
- return inlayModel.getHeightOfBlockElementsBeforeVisualLine(visualLine, startOffset, prevFoldRegionIndex)
- }
-
- override fun dispose() {
- }
-
- // region Not yet implemented
-
- override fun addInlineElement(offset: Int, relatesToPrecedingText: Boolean, renderer: T & Any): Inlay? {
- TODO("Not yet implemented")
- }
-
- override fun addInlineElement(offset: Int, relatesToPrecedingText: Boolean, priority: Int, renderer: T & Any): Inlay? {
- TODO("Not yet implemented")
- }
-
- override fun addInlineElement(offset: Int, properties: InlayProperties, renderer: T & Any): Inlay? {
- TODO("Not yet implemented")
- }
-
- override fun addBlockElement(offset: Int, relatesToPrecedingText: Boolean, showAbove: Boolean, priority: Int, renderer: T & Any): Inlay? {
- TODO("Not yet implemented")
- }
-
- override fun addBlockElement(offset: Int, properties: InlayProperties, renderer: T & Any): Inlay? {
- TODO("Not yet implemented")
- }
-
- override fun addAfterLineEndElement(offset: Int, relatesToPrecedingText: Boolean, renderer: T & Any): Inlay? {
- TODO("Not yet implemented")
- }
-
- override fun addAfterLineEndElement(offset: Int, properties: InlayProperties, renderer: T & Any): Inlay? {
- TODO("Not yet implemented")
- }
-
- override fun hasInlineElementAt(offset: Int): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun getInlineElementAt(visualPosition: VisualPosition): Inlay<*>? {
- TODO("Not yet implemented")
- }
-
- override fun getElementAt(point: Point): Inlay<*>? {
- TODO("Not yet implemented")
- }
-
- override fun setConsiderCaretPositionOnDocumentUpdates(enabled: Boolean) {
- TODO("Not yet implemented")
- }
-
- override fun execute(batchMode: Boolean, operation: Runnable) {
- TODO("Not yet implemented")
- }
-
- // endregion
-}
-
-private class AdInlay(
- private val offset: Int,
- private val origin: Inlay,
-) : Inlay {
-
- override fun getOffset(): Int {
- return offset
- }
-
- override fun getHeightInPixels(): Int {
- return origin.getHeightInPixels()
- }
-
- override fun getRenderer(): T {
- return origin.getRenderer()
- }
-
- override fun getWidthInPixels(): Int {
- return origin.getWidthInPixels()
- }
-
- override fun getPlacement(): Inlay.Placement {
- return origin.getPlacement()
- }
-
- override fun isRelatedToPrecedingText(): Boolean {
- return origin.isRelatedToPrecedingText()
- }
-
- override fun isValid(): Boolean {
- return origin.isValid
- }
-
- override fun getUserData(key: Key): T? {
- return origin.getUserData(key)
- }
-
- override fun getEditor(): Editor {
- return origin.editor
- }
-
- // region Not yet implemented
-
- override fun getVisualPosition(): VisualPosition {
- TODO("Not yet implemented")
- }
-
- override fun getBounds(): Rectangle? {
- TODO("Not yet implemented")
- }
-
- override fun getGutterIconRenderer(): GutterIconRenderer? {
- TODO("Not yet implemented")
- }
-
- override fun update() {
- TODO("Not yet implemented")
- }
-
- override fun repaint() {
- TODO("Not yet implemented")
- }
-
- override fun dispose() {
- TODO("Not yet implemented")
- }
-
- override fun putUserDataIfAbsent(key: Key, value: T & Any): T & Any {
- TODO("Not yet implemented")
- }
-
- override fun replace(key: Key, oldValue: T?, newValue: T?): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun putUserData(key: Key, value: T?) {
- TODO("Not yet implemented")
- }
-
- // endregion
-}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdMarkupModel.kt b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdMarkupModel.kt
deleted file mode 100644
index 9a810ece516d..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdMarkupModel.kt
+++ /dev/null
@@ -1,408 +0,0 @@
-// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.openapi.editor.impl.ad
-
-import andel.editor.RangeMarkerId
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.editor.Document
-import com.intellij.openapi.editor.colors.EditorColorsScheme
-import com.intellij.openapi.editor.colors.TextAttributesKey
-import com.intellij.openapi.editor.ex.MarkupIterator
-import com.intellij.openapi.editor.ex.MarkupModelEx
-import com.intellij.openapi.editor.ex.RangeHighlighterEx
-import com.intellij.openapi.editor.impl.event.MarkupModelListener
-import com.intellij.openapi.editor.markup.*
-import com.intellij.openapi.util.Key
-import com.intellij.openapi.util.NlsContexts
-import com.intellij.openapi.util.TextRange
-import com.intellij.util.Consumer
-import com.intellij.util.Processor
-import com.jetbrains.rhizomedb.ChangeScope
-import fleet.kernel.change
-import fleet.kernel.shared
-import fleet.util.UID
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
-import org.jetbrains.annotations.ApiStatus
-import java.awt.Color
-import andel.text.TextRange as AndelTextRange
-
-
-@ApiStatus.Experimental
-internal class AdMarkupModel private constructor(
- private val adDocument: AdDocument,
- private val mapper: AdRangeMapper,
- markupModel: MarkupModelEx,
- private val coroutineScope: CoroutineScope,
- private val repaintLambda: suspend () -> Unit,
-) : MarkupModelEx, Disposable {
-
- companion object {
- fun fromMarkup(
- markupModel: MarkupModelEx,
- adDocument: AdDocument,
- coroutineScope: CoroutineScope,
- repaintLambda: suspend () -> Unit,
- ): AdMarkupModel {
- val mapper = addExistingHighlighters(markupModel, adDocument)
- val adMarkupModel = AdMarkupModel(adDocument, mapper, markupModel, coroutineScope, repaintLambda)
- return adMarkupModel
- }
-
- private fun addExistingHighlighters(markupModel: MarkupModelEx, adDocument: AdDocument): AdRangeMapper {
- // TODO: there is a gap between allHighlighters and addMarkupModelListener, a highlighter may be missed
- val mapper = AdRangeMapper()
- val rangesIds = mutableListOf()
- val ranges = mutableListOf()
- for (highlighter in markupModel.allHighlighters) {
- if (highlighter.isValid) {
- val rangeId = UID.random()
- rangesIds.add(RangeMarkerId(rangeId))
- ranges.add(AndelTextRange(highlighter.startOffset, highlighter.endOffset))
- mapper.register(rangeId, highlighter as RangeHighlighterEx)
- }
- }
- adDocument.addRangeMarkers(rangesIds, ranges)
- return mapper
- }
- }
-
- init {
- markupModel.addMarkupModelListener(this, object : MarkupModelListener {
- override fun afterAdded(highlighter: RangeHighlighterEx) {
- onHighlightUpdate {
- // TODO: incorrect offset -> ui offset
- val rangeId = UID.random()
- adDocument.addRangeMarker(
- RangeMarkerId(rangeId),
- highlighter.startOffset.toLong(),
- highlighter.endOffset.toLong(),
- )
- mapper.register(rangeId, highlighter)
- }
- }
- override fun afterRemoved(highlighter: RangeHighlighterEx) {
- onHighlightUpdate {
- val rangeId = mapper.unregister(highlighter)
- if (rangeId != null) {
- adDocument.removeRangeMarker(RangeMarkerId(rangeId))
- }
- }
- }
- })
- }
-
- override fun processRangeHighlightersOverlappingWith(
- start: Int,
- end: Int,
- processor: Processor,
- ): Boolean {
- for (interval in adDocument.queryRangeMarkers(start.toLong(), end.toLong())) {
- val rh = mapper.resolveRange(interval.id)
- if (rh != null && rh.isValid) {
- val startOffset = interval.from.toInt()
- val endOffset = interval.to.toInt()
- val proceed = processor.process(AdRangeHighlighter(
- startOffset,
- endOffset,
- affectedStartOffset(startOffset, rh.targetArea),
- affectedEndOffset(endOffset, rh.targetArea),
- rh
- ))
- if (!proceed) {
- break
- }
- }
- }
- return true
- }
-
- override fun dispose() {
- }
-
- private fun onHighlightUpdate(body: ChangeScope.() -> Unit) {
- coroutineScope.launch {
- change {
- shared {
- body()
- }
- }
- repaintLambda.invoke()
- }
- }
-
- private fun affectedStartOffset(startOffset: Int, area: HighlighterTargetArea): Int {
- if (area == HighlighterTargetArea.EXACT_RANGE) {
- return startOffset
- }
- val line = adDocument.getLineNumber(startOffset)
- return adDocument.getLineStartOffset(line)
- }
-
- private fun affectedEndOffset(endOffset: Int, area: HighlighterTargetArea): Int {
- if (area == HighlighterTargetArea.EXACT_RANGE) {
- return endOffset
- }
- val line = adDocument.getLineNumber(endOffset)
- return adDocument.getLineEndOffset(line)
- }
-
- // region Not yet implemented
-
- override fun addPersistentLineHighlighter(textAttributesKey: TextAttributesKey?, lineNumber: Int, layer: Int): RangeHighlighterEx? {
- TODO("Not yet implemented")
- }
-
- override fun addPersistentLineHighlighter(lineNumber: Int, layer: Int, textAttributes: TextAttributes?): RangeHighlighterEx? {
- TODO("Not yet implemented")
- }
-
- override fun containsHighlighter(highlighter: RangeHighlighter): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun addMarkupModelListener(parentDisposable: Disposable, listener: MarkupModelListener) {
- TODO("Not yet implemented")
- }
-
- override fun setRangeHighlighterAttributes(highlighter: RangeHighlighter, textAttributes: TextAttributes) {
- TODO("Not yet implemented")
- }
-
- override fun processRangeHighlightersOutside(start: Int, end: Int, processor: Processor): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun overlappingIterator(startOffset: Int, endOffset: Int): MarkupIterator {
- TODO("Not yet implemented")
- }
-
- override fun addRangeHighlighterAndChangeAttributes(textAttributesKey: TextAttributesKey?, startOffset: Int, endOffset: Int, layer: Int, targetArea: HighlighterTargetArea, isPersistent: Boolean, changeAttributesAction: Consumer?): RangeHighlighterEx {
- TODO("Not yet implemented")
- }
-
- override fun changeAttributesInBatch(highlighter: RangeHighlighterEx, changeAttributesAction: Consumer) {
- TODO("Not yet implemented")
- }
-
- override fun getDocument(): Document {
- TODO("Not yet implemented")
- }
-
- override fun addRangeHighlighter(textAttributesKey: TextAttributesKey?, startOffset: Int, endOffset: Int, layer: Int, targetArea: HighlighterTargetArea): RangeHighlighter {
- TODO("Not yet implemented")
- }
-
- override fun addRangeHighlighter(startOffset: Int, endOffset: Int, layer: Int, textAttributes: TextAttributes?, targetArea: HighlighterTargetArea): RangeHighlighter {
- TODO("Not yet implemented")
- }
-
- override fun addLineHighlighter(textAttributesKey: TextAttributesKey?, line: Int, layer: Int): RangeHighlighter {
- TODO("Not yet implemented")
- }
-
- override fun addLineHighlighter(line: Int, layer: Int, textAttributes: TextAttributes?): RangeHighlighter {
- TODO("Not yet implemented")
- }
-
- override fun removeHighlighter(rangeHighlighter: RangeHighlighter) {
- TODO("Not yet implemented")
- }
-
- override fun removeAllHighlighters() {
- TODO("Not yet implemented")
- }
-
- override fun getAllHighlighters(): Array {
- TODO("Not yet implemented")
- }
-
- override fun getUserData(key: Key): T? {
- TODO("Not yet implemented")
- }
-
- override fun putUserData(key: Key, value: T?) {
- TODO("Not yet implemented")
- }
-
- // endregion
-}
-
-private class AdRangeHighlighter(
- private val startOffset: Int,
- private val endOffset: Int,
- private val startAffectedOffset: Int,
- private val endAffectedOffset: Int,
- private val origin: RangeHighlighterEx,
-) : RangeHighlighterEx by origin {
-
- override fun isValid(): Boolean = true
- override fun getStartOffset(): Int = startOffset
- override fun getEndOffset(): Int = endOffset
- override fun getAffectedAreaStartOffset(): Int = startAffectedOffset
- override fun getAffectedAreaEndOffset(): Int = endAffectedOffset
-
- override fun getCustomRenderer(): CustomHighlighterRenderer? = origin.customRenderer // TODO
- override fun getLineSeparatorPlacement(): SeparatorPlacement? = origin.lineSeparatorPlacement // TODO
- override fun getLineSeparatorRenderer(): LineSeparatorRenderer? = origin.lineSeparatorRenderer // TODO
-
- override fun getLineSeparatorColor(): Color? = origin.lineSeparatorColor
- override fun isAfterEndOfLine(): Boolean = origin.isAfterEndOfLine
- override fun getTextAttributes(scheme: EditorColorsScheme?): TextAttributes? = origin.getTextAttributes(scheme)
- override fun isVisibleIfFolded(): Boolean = origin.isVisibleIfFolded
- override fun getLayer(): Int = origin.layer
- override fun getTargetArea(): HighlighterTargetArea = origin.targetArea
- override fun getErrorStripeTooltip(): Any? = origin.errorStripeTooltip
-
- // region Not yet implemented
-
- override fun getId(): Long {
- TODO("Not yet implemented")
- }
-
- override fun getTextRange(): TextRange {
- TODO("Not yet implemented")
- }
-
- override fun getForcedTextAttributes(): TextAttributes? {
- TODO("Not yet implemented")
- }
-
- override fun getForcedErrorStripeMarkColor(): Color? {
- TODO("Not yet implemented")
- }
-
- override fun setAfterEndOfLine(value: Boolean) {
- TODO("Not yet implemented")
- }
-
- override fun fireChanged(renderersChanged: Boolean, fontStyleChanged: Boolean, foregroundColorChanged: Boolean) {
- TODO("Not yet implemented")
- }
-
- override fun setTextAttributes(textAttributes: TextAttributes?) {
- TODO("Not yet implemented")
- }
-
- override fun setVisibleIfFolded(value: Boolean) {
- TODO("Not yet implemented")
- }
-
- override fun isPersistent(): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun isRenderedInGutter(): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun copyFrom(other: RangeHighlighterEx) {
- TODO("Not yet implemented")
- }
-
- override fun getTextAttributesKey(): TextAttributesKey? {
- TODO("Not yet implemented")
- }
-
- override fun setTextAttributesKey(textAttributesKey: TextAttributesKey) {
- TODO("Not yet implemented")
- }
-
- @Suppress("OVERRIDE_DEPRECATION")
- override fun getTextAttributes(): TextAttributes? {
- TODO("Not yet implemented")
- }
-
- override fun getLineMarkerRenderer(): LineMarkerRenderer? {
- TODO("Not yet implemented")
- }
-
- override fun setLineMarkerRenderer(renderer: LineMarkerRenderer?) {
- TODO("Not yet implemented")
- }
-
- override fun setCustomRenderer(renderer: CustomHighlighterRenderer?) {
- TODO("Not yet implemented")
- }
-
- override fun getGutterIconRenderer(): GutterIconRenderer? {
- TODO("Not yet implemented")
- }
-
- override fun setGutterIconRenderer(renderer: GutterIconRenderer?) {
- TODO("Not yet implemented")
- }
-
- override fun getErrorStripeMarkColor(scheme: EditorColorsScheme?): Color? {
- TODO("Not yet implemented")
- }
-
- override fun setErrorStripeMarkColor(color: Color?) {
- TODO("Not yet implemented")
- }
-
- override fun setErrorStripeTooltip(tooltipObject: @NlsContexts.Tooltip Any?) {
- TODO("Not yet implemented")
- }
-
- override fun isThinErrorStripeMark(): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun setThinErrorStripeMark(value: Boolean) {
- TODO("Not yet implemented")
- }
-
- override fun setLineSeparatorColor(color: Color?) {
- TODO("Not yet implemented")
- }
-
- override fun setLineSeparatorRenderer(renderer: LineSeparatorRenderer?) {
- TODO("Not yet implemented")
- }
-
- override fun setLineSeparatorPlacement(placement: SeparatorPlacement?) {
- TODO("Not yet implemented")
- }
-
- override fun setEditorFilter(filter: MarkupEditorFilter) {
- TODO("Not yet implemented")
- }
-
- override fun getEditorFilter(): MarkupEditorFilter {
- TODO("Not yet implemented")
- }
-
- override fun getDocument(): Document {
- TODO("Not yet implemented")
- }
-
- override fun setGreedyToLeft(greedy: Boolean) {
- TODO("Not yet implemented")
- }
-
- override fun setGreedyToRight(greedy: Boolean) {
- TODO("Not yet implemented")
- }
-
- override fun isGreedyToRight(): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun isGreedyToLeft(): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun dispose() {
- TODO("Not yet implemented")
- }
-
- override fun getUserData(key: Key): T? {
- TODO("Not yet implemented")
- }
-
- override fun putUserData(key: Key, value: T?) {
- TODO("Not yet implemented")
- }
-
- // endregion
-}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdRangeMapper.kt b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdRangeMapper.kt
deleted file mode 100644
index 35482dcfdd00..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdRangeMapper.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.openapi.editor.impl.ad
-
-import fleet.util.UID
-import java.util.concurrent.ConcurrentHashMap
-
-internal class AdRangeMapper {
- private val idToRange = ConcurrentHashMap()
- private val rangeToId = ConcurrentHashMap()
-
- fun resolveRange(id: UID): T? {
- return idToRange[id]
- }
-
- fun register(id: UID, range: T) {
- idToRange.put(id, range)
- rangeToId.put(range, id)
- }
-
- fun unregister(range: T): UID? {
- val id = rangeToId.remove(range)
- if (id != null) {
- idToRange.remove(id)
- }
- return id
- }
-}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/v2/AdTheManagerV2.kt b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdTheManager.kt
similarity index 86%
rename from platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/v2/AdTheManagerV2.kt
rename to platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdTheManager.kt
index b2adba029ad2..e5963caf3524 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/v2/AdTheManagerV2.kt
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdTheManager.kt
@@ -1,8 +1,6 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.openapi.editor.impl.ad.v2
+package com.intellij.openapi.editor.impl.ad
-import andel.intervals.AnchorStorage
-import andel.text.Text
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.isRhizomeAdEnabled
@@ -13,24 +11,16 @@ import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ex.DocumentEx
import com.intellij.openapi.editor.ex.util.EditorUtil
-import com.intellij.openapi.editor.impl.ad.ThreadLocalRhizomeDB
import com.intellij.openapi.fileEditor.FileDocumentManager
-import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.ide.progress.ModalTaskOwner
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
import com.intellij.platform.pasta.common.DocumentEntity
-import com.intellij.platform.pasta.common.DocumentEntity.Companion.EditLogAttr
-import com.intellij.platform.pasta.common.DocumentEntity.Companion.SharedAnchorStorageAttr
-import com.intellij.platform.pasta.common.DocumentEntity.Companion.TextAttr
-import com.intellij.platform.pasta.common.DocumentEntity.Companion.WritableAttr
-import com.intellij.platform.pasta.common.createEmptyEditLog
import com.intellij.platform.util.coroutines.childScope
import com.intellij.util.awaitCancellationAndInvoke
import com.intellij.util.concurrency.AppExecutorUtil
import com.intellij.util.concurrency.ThreadingAssertions
import com.intellij.util.ui.EDT
-import fleet.kernel.Durable
import fleet.kernel.change
import fleet.kernel.rete.each
import fleet.kernel.rete.filter
@@ -49,11 +39,11 @@ private val AD_DISPATCHER by lazy {
@Experimental
@Service(Level.APP)
-class AdTheManagerV2(private val coroutineScope: CoroutineScope) {
+class AdTheManager(private val coroutineScope: CoroutineScope) {
companion object {
@JvmStatic
- fun getInstance(): AdTheManagerV2 = service()
+ fun getInstance(): AdTheManager = service()
}
private val docToHandle = IdentityHashMap()
@@ -119,7 +109,7 @@ class AdTheManagerV2(private val coroutineScope: CoroutineScope) {
}?.entity()
if (entity != null) {
ThreadLocalRhizomeDB.setThreadLocalDb(ThreadLocalRhizomeDB.lastKnownDb())
- return AdDocumentV2(entity)
+ return AdDocument(entity)
}
}
return null
@@ -157,13 +147,7 @@ class AdTheManagerV2(private val coroutineScope: CoroutineScope) {
createEntity = { entityId ->
change {
shared {
- DocumentEntity.new {
- it[Durable.Id] = entityId
- it[TextAttr] = Text.fromString(text.toString())
- it[WritableAttr] = true
- it[EditLogAttr] = createEmptyEditLog()
- it[SharedAnchorStorageAttr] = AnchorStorage.empty()
- }
+ DocumentEntity.fromText(entityId, text.toString())
}
}
},
@@ -203,7 +187,7 @@ class AdTheManagerV2(private val coroutineScope: CoroutineScope) {
entity
}
if (bindType != BindType.FRONTEND) {
- val documentListener = AdDocumentSynchronizerV2(documentId, entityId, cs, entityDeferred)
+ val documentListener = AdDocumentSynchronizer(documentId, entityId, cs, entityDeferred)
document.addDocumentListener(documentListener)
@Suppress("OPT_IN_USAGE")
cs.awaitCancellationAndInvoke {
@@ -240,7 +224,7 @@ class AdTheManagerV2(private val coroutineScope: CoroutineScope) {
}
private fun isEnabled(): Boolean {
- return isRhizomeAdEnabled && Registry.`is`("ijpl.rhizome.ad.v2.enabled", false)
+ return isRhizomeAdEnabled
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdTheManagerImpl.kt b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdTheManagerImpl.kt
deleted file mode 100644
index 2b09ce5576de..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/AdTheManagerImpl.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.openapi.editor.impl.ad
-
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.application.EDT
-import com.intellij.openapi.application.isRhizomeAdEnabled
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.components.Service.Level
-import com.intellij.openapi.editor.CaretModel
-import com.intellij.openapi.editor.Document
-import com.intellij.openapi.editor.ScrollingModel
-import com.intellij.openapi.editor.SelectionModel
-import com.intellij.openapi.editor.ex.*
-import com.intellij.openapi.editor.highlighter.EditorHighlighter
-import com.intellij.openapi.editor.impl.DocumentImpl
-import com.intellij.openapi.editor.impl.EditorImpl
-import com.intellij.openapi.editor.impl.FocusModeModel
-import com.intellij.openapi.util.Disposer
-import com.intellij.platform.kernel.withKernel
-import com.intellij.platform.util.coroutines.childScope
-import com.intellij.util.concurrency.AppExecutorUtil
-import com.intellij.util.concurrency.ThreadingAssertions
-import com.jetbrains.rhizomedb.ChangeScope
-import com.jetbrains.rhizomedb.asOf
-import fleet.kernel.change
-import fleet.kernel.lastKnownDb
-import fleet.kernel.shared
-import fleet.kernel.transactor
-import kotlinx.coroutines.*
-
-
-private val LIMITED_DISPATCHER by lazy {
- AppExecutorUtil.createBoundedApplicationPoolExecutor("AD_DISPATCHER", 1).asCoroutineDispatcher()
-}
-
-@Service(Level.PROJECT)
-internal class AdTheManagerImpl(private val coroutineScope: CoroutineScope) : AdTheManager {
-
- override fun createEditorModel(editor: EditorEx): EditorModel? {
- ThreadingAssertions.assertEventDispatchThread()
- if (isRhizomeAdEnabled && editor is EditorImpl && isDocumentGuardedByLock(editor.document)) {
- val editorScope = this.coroutineScope.childScope("CoroutineScope for $editor", LIMITED_DISPATCHER)
- val modStampBefore = editor.document.modificationStamp
- @Suppress("RAW_RUN_BLOCKING")
- val editorModel = runBlocking {
- withKernel {
- change {
- shared {
- createEditorModelImpl(editor, editorScope)
- }
- }
- }
- }
- ThreadLocalRhizomeDB.setThreadLocalDb(ThreadLocalRhizomeDB.lastKnownDb())
-
- val documentSynchronizer = AdDocumentSynchronizer(editorModel.document as AdDocument, editorScope) {
- repaintEditor(editor)
- }
- editor.document.addDocumentListener(documentSynchronizer, documentSynchronizer)
-
- Disposer.register(editorModel, documentSynchronizer)
- Disposer.register(editorModel, editorModel.editorMarkupModel as Disposable)
- Disposer.register(editorModel, editorModel.documentMarkupModel as Disposable)
- Disposer.register(editorModel, editorModel.inlayModel as Disposable)
- Disposer.register(editor.disposable, editorModel)
-
- assert(editor.document.modificationStamp == modStampBefore)
-
- return editorModel
- }
- return null
- }
-
- private fun ChangeScope.createEditorModelImpl(editor: EditorImpl, coroutineScope: CoroutineScope): EditorModel {
- register(AdDocumentEntity)
- val document = editor.document
- val entity = AdDocumentEntity.fromString(
- document.immutableCharSequence.toString(),
- document.modificationStamp,
- )
- val adDocument = AdDocument(debugName(document), entity)
-
- fun createMarkup(markupModel: MarkupModelEx) = AdMarkupModel.fromMarkup(
- markupModel,
- adDocument,
- coroutineScope
- ) { repaintEditor(editor) }
-
- val editorMarkup = createMarkup(editor.markupModel)
- val documentMarkup = createMarkup(editor.filteredDocumentMarkupModel)
-
- val inlayModel = AdInlayModel.fromInlays(
- editor.inlayModel,
- adDocument,
- coroutineScope
- ) { repaintEditor(editor) }
-
- return object : EditorModel {
- override fun getDocument(): DocumentEx = adDocument
- override fun getEditorMarkupModel(): MarkupModelEx = editorMarkup
- override fun getDocumentMarkupModel(): MarkupModelEx = documentMarkup
- override fun getHighlighter(): EditorHighlighter = editor.highlighter
- override fun getInlayModel(): InlayModelEx = inlayModel
- override fun getFoldingModel(): FoldingModelEx = editor.foldingModel
- override fun getSoftWrapModel(): SoftWrapModelEx = editor.softWrapModel
- override fun getCaretModel(): CaretModel = editor.caretModel
- override fun getSelectionModel(): SelectionModel = editor.selectionModel
- override fun getScrollingModel(): ScrollingModel = editor.scrollingModel
- override fun getFocusModel(): FocusModeModel = editor.focusModeModel
- override fun isAd(): Boolean = true
- override fun dispose() {
- coroutineScope.cancel()
- this@AdTheManagerImpl.coroutineScope.launch {
- change {
- shared {
- entity.delete()
- }
- }
- }
- }
- }
- }
-
- private suspend fun repaintEditor(editor: EditorImpl) {
- val lastKnownDb = transactor().lastKnownDb
- withContext(Dispatchers.EDT) {
- if (!editor.isDisposed) {
- asOf(lastKnownDb) {
- editor.component.repaint()
- }
- }
- }
- }
-
- private fun isDocumentGuardedByLock(document: Document): Boolean {
- return document is DocumentImpl && document.isWriteThreadOnly
- }
-
- private fun debugName(document: Document): String {
- val hash = Integer.toHexString(System.identityHashCode(document))
- return document.toString().replace("DocumentImpl", "AdDocument@$hash")
- }
-}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/v2/AdDocumentSynchronizerV2.kt b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/v2/AdDocumentSynchronizerV2.kt
deleted file mode 100644
index 499bfdb7f28a..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/v2/AdDocumentSynchronizerV2.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.openapi.editor.impl.ad.v2
-
-import andel.operation.Operation
-import com.intellij.openapi.editor.event.DocumentEvent
-import com.intellij.openapi.editor.ex.PrioritizedDocumentListener
-import com.intellij.openapi.editor.impl.ad.ThreadLocalRhizomeDB
-import com.intellij.platform.pasta.common.DocumentEntity
-import fleet.kernel.awaitCommitted
-import fleet.kernel.change
-import fleet.util.UID
-import fleet.util.openmap.OpenMap
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.async
-import kotlinx.coroutines.runBlocking
-import org.jetbrains.annotations.ApiStatus.Experimental
-
-
-@Experimental
-internal data class AdDocumentSynchronizerV2(
- private val documentId: Any, // RdDocumentId
- private val entityId: UID,
- private val coroutineScope: CoroutineScope,
- private val entityDeferred: Deferred,
-): PrioritizedDocumentListener {
-
- override fun getPriority(): Int = Int.MIN_VALUE + 1
-
- override fun documentChanged(event: DocumentEvent) {
- val entityChange = coroutineScope.async {
- val operation = operation(event)
- val entity = entityDeferred.await()
- change { // it is a shared change
- entity.mutate(this, OpenMap.empty()) {
- edit(operation)
- }
- }
- awaitCommitted()
- }
- // TODO: pumping events in runWithModalProgressBlocking ruins the models
- //@Suppress("HardCodedStringLiteral")
- //runWithModalProgressBlocking(
- // ModalTaskOwner.guess(),
- // "Shared document entity synchronization $entityId",
- //) { entityChange.await() }
- runBlocking { entityChange.await() }
- ThreadLocalRhizomeDB.setThreadLocalDb(ThreadLocalRhizomeDB.lastKnownDb())
- }
-
- private fun operation(event: DocumentEvent): Operation {
- val oldFragment = event.oldFragment.toString()
- val newFragment = event.newFragment.toString()
- val lengthBefore = event.document.textLength - newFragment.length + oldFragment.length
- return Operation.Companion.replaceAt(
- offset = event.offset.toLong(),
- oldText = oldFragment,
- newText = newFragment,
- totalLength = lengthBefore.toLong(),
- )
- }
-}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/v2/AdDocumentV2.kt b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/v2/AdDocumentV2.kt
deleted file mode 100644
index e22b75d7bcc7..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/v2/AdDocumentV2.kt
+++ /dev/null
@@ -1,315 +0,0 @@
-// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.openapi.editor.impl.ad.v2
-
-import andel.text.*
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.editor.RangeMarker
-import com.intellij.openapi.editor.event.DocumentListener
-import com.intellij.openapi.editor.ex.DocumentEx
-import com.intellij.openapi.editor.ex.EditReadOnlyListener
-import com.intellij.openapi.editor.ex.LineIterator
-import com.intellij.openapi.editor.ex.RangeMarkerEx
-import com.intellij.platform.pasta.common.DocumentEntity
-import com.intellij.openapi.util.Key
-import com.intellij.openapi.util.TextRange
-import com.intellij.util.Processor
-import org.jetbrains.annotations.ApiStatus.Experimental
-import java.beans.PropertyChangeListener
-import java.util.*
-
-@Experimental
-internal class AdDocumentV2(private val entity: DocumentEntity) : DocumentEx {
-
- // region TEXT
-
- override fun getText(range: TextRange): String {
- return textView().string(range.startOffset, range.endOffset)
- }
-
- override fun getImmutableCharSequence(): CharSequence {
- return textView().charSequence()
- }
-
- override fun getTextLength(): Int {
- return text().charCount
- }
-
- // endregion
-
-
- //region LINES
-
- override fun getLineCount(): Int {
- val text = text()
- if (text.charCount == 0) {
- return 0
- }
- return text.lineCount.line
- }
-
- override fun getLineNumber(offset: Int): Int {
- return textView().lineAt(offset).line
- }
-
- override fun getLineStartOffset(line: Int): Int {
- return textView().lineStartOffset(line.line)
- }
-
- override fun getLineEndOffset(line: Int): Int {
- return textView().lineEndOffset(line.line)
- }
-
- override fun getLineSeparatorLength(line: Int): Int {
- // TODO: optimize
- return textView().lineEndOffset(line.line, includeLineSeparator=true) -
- textView().lineEndOffset(line.line, includeLineSeparator=false)
- }
-
- override fun createLineIterator(): LineIterator {
- TODO("Not yet implemented")
- }
-
- //endregion
-
-
- //region MUTATE TEXT
-
- override fun insertString(offset: Int, chars: CharSequence) {
- TODO("Not yet implemented")
- }
-
- override fun deleteString(startOffset: Int, endOffset: Int) {
- TODO("Not yet implemented")
- }
-
- override fun replaceString(startOffset: Int, endOffset: Int, chars: CharSequence) {
- TODO("Not yet implemented")
- }
-
- override fun setText(chars: CharSequence) {
- TODO("Not yet implemented")
- }
-
- override fun replaceText(chars: CharSequence, newModificationStamp: Long) {
- TODO("Not yet implemented")
- }
-
- //endregion
-
-
- //region RANGE MARKERS
-
- override fun createRangeMarker(startOffset: Int, endOffset: Int, surviveOnExternalChange: Boolean): RangeMarkerEx {
- TODO("Not yet implemented")
- }
-
- override fun registerRangeMarker(rangeMarker: RangeMarkerEx, start: Int, end: Int, greedyToLeft: Boolean, greedyToRight: Boolean, layer: Int) {
- TODO("Not yet implemented")
- }
-
- override fun removeRangeMarker(rangeMarker: RangeMarkerEx): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun processRangeMarkers(processor: Processor): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun processRangeMarkersOverlappingWith(start: Int, end: Int, processor: Processor): Boolean {
- TODO("Not yet implemented")
- }
-
- //endregion
-
-
- //region DOC LISTENERS
-
- override fun addDocumentListener(listener: DocumentListener, parentDisposable: Disposable) {
- //TODO("Not yet implemented")
- }
-
- override fun addDocumentListener(listener: DocumentListener) {
- //TODO("Not yet implemented")
- }
-
- override fun removeDocumentListener(listener: DocumentListener) {
- //TODO("Not yet implemented")
- }
-
- //endregion
-
-
- //region PROP LISTENER
-
- override fun addPropertyChangeListener(listener: PropertyChangeListener) {
- TODO("Not yet implemented")
- }
-
- override fun removePropertyChangeListener(listener: PropertyChangeListener) {
- TODO("Not yet implemented")
- }
-
- //endregion
-
-
- //region TRACK MODIFICATIONS
-
- override fun isLineModified(line: Int): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun getModificationStamp(): Long {
- return documentRead {
- entity.editLog.timestamp
- }
- }
-
- override fun setModificationStamp(modificationStamp: Long) {
- TODO("Not yet implemented")
- }
-
- override fun clearLineModificationFlags() {
- TODO("Not yet implemented")
- }
-
- override fun getModificationSequence(): Int {
- TODO("Not yet implemented")
- }
-
- //endregion
-
-
- //region GUARDED BLOCKS
-
- override fun createGuardedBlock(startOffset: Int, endOffset: Int): RangeMarker {
- TODO("Not yet implemented")
- }
-
- override fun removeGuardedBlock(block: RangeMarker) {
- TODO("Not yet implemented")
- }
-
- override fun getOffsetGuard(offset: Int): RangeMarker? {
- TODO("Not yet implemented")
- }
-
- override fun getRangeGuard(start: Int, end: Int): RangeMarker? {
- TODO("Not yet implemented")
- }
-
- override fun getGuardedBlocks(): List {
- // TODO("Not yet implemented")
- return Collections.emptyList()
- }
-
- override fun startGuardedBlockChecking() {
- TODO("Not yet implemented")
- }
-
- override fun stopGuardedBlockChecking() {
- TODO("Not yet implemented")
- }
-
- override fun suppressGuardedExceptions() {
- TODO("Not yet implemented")
- }
-
- override fun unSuppressGuardedExceptions() {
- TODO("Not yet implemented")
- }
-
- //endregion
-
-
- //region BULK MODE
-
- override fun isInBulkUpdate(): Boolean {
- return false // TODO("Not yet implemented")
- }
-
- @Deprecated("Deprecated in Java")
- override fun setInBulkUpdate(value: Boolean) {
- TODO("Not yet implemented")
- }
-
- override fun isInEventsHandling(): Boolean {
- TODO("Not yet implemented")
- }
-
- //endregion
-
-
- //region READ-ONLY MODE
-
- override fun setReadOnly(isReadOnly: Boolean) {
- TODO("Not yet implemented")
- }
-
- override fun isWritable(): Boolean {
- TODO("Not yet implemented")
- }
-
- //endregion
-
-
- //region SPECIAL MODES
-
- override fun setCyclicBufferSize(bufferSize: Int) {
- TODO("Not yet implemented")
- }
-
- override fun setStripTrailingSpacesEnabled(isEnabled: Boolean) {
- TODO("Not yet implemented")
- }
-
- //endregion
-
-
- //region READ ATTEMPT
-
- override fun fireReadOnlyModificationAttempt() {
- TODO("Not yet implemented")
- }
-
- override fun addEditReadOnlyListener(listener: EditReadOnlyListener) {
- TODO("Not yet implemented")
- }
-
- override fun removeEditReadOnlyListener(listener: EditReadOnlyListener) {
- TODO("Not yet implemented")
- }
-
- //endregion
-
-
- //region USER DATA
-
- override fun getUserData(key: Key): T? {
- TODO("Not yet implemented")
- }
-
- override fun putUserData(key: Key, value: T?) {
- TODO("Not yet implemented")
- }
-
- //endregion
-
-
- //region PRIVATE
-
- private fun text(): Text {
- return documentRead {
- entity.text
- }
- }
-
- private fun textView(): TextView {
- return text().view()
- }
-
- private fun documentRead(block: () -> T): T {
- return block()
- }
-
- //endregion
-}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/v2/package-info.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/v2/package-info.java
deleted file mode 100644
index f25ece7f914c..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ad/v2/package-info.java
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-@ApiStatus.Experimental
-@ApiStatus.Internal
-package com.intellij.openapi.editor.impl.ad.v2;
-
-import org.jetbrains.annotations.ApiStatus;
diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties
index c7ae9191afc9..71f748b7cec6 100644
--- a/platform/util/resources/misc/registry.properties
+++ b/platform/util/resources/misc/registry.properties
@@ -2481,11 +2481,6 @@ ide.show.files.action=true
ide.showing.scope.compatibility.mode=false
ide.showing.scope.compatibility.mode.description=Turns on compatibility implementation of `showingScope` using newer `launchOnShow`.
-ijpl.rhizome.ad.debug.enabled=false
-ijpl.rhizome.ad.debug.enabled.description=Debug mode for IJPL-54
-ijpl.rhizome.ad.v2.enabled=false
-ijpl.rhizome.ad.v2.enabled.description=Second version of IJPL-54 based on common fleet entity. NOTE: must be enabled on FE and BE
-
thumbnails.toolwindow.enabled=false
thumbnails.toolwindow.enabled.description=Enables the Thumbnails toolwindows and related functionality