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