mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
[PyCharm] Jupyter (refactor): From EditorCell removed 'mode' and NotebookCellInlayManager lost subscription to NOTEBOOK_EDITOR_MODE. #PY-76627 Fixed
Also small refactor of HeadingInfo and a system of extensions in EditorCell. (cherry picked from commit c7817c899947c94aa7d288d757cb6b642941414c) (cherry picked from commit a2a93f22e6a6d264785a9ea236b1689bd69b88cf) IJ-CR-147319 GitOrigin-RevId: e99bfb9ce00f69cf3679b0f3f12ca06e9d7d1a24
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5bf8a16266
commit
8514cdbb1a
@@ -13,10 +13,10 @@ import com.intellij.openapi.editor.ex.EditorEx
|
||||
import com.intellij.openapi.editor.ex.MarkupModelEx
|
||||
import com.intellij.openapi.editor.ex.RangeHighlighterEx
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.ui.Gray
|
||||
import com.intellij.util.concurrency.ThreadingAssertions
|
||||
import com.intellij.util.concurrency.annotations.RequiresEdt
|
||||
import com.intellij.util.messages.Topic
|
||||
import java.awt.Color
|
||||
|
||||
/**
|
||||
* The Jupyter Notebook has a modal user interface.
|
||||
@@ -37,7 +37,6 @@ val NOTEBOOK_EDITOR_MODE: Topic<NotebookEditorModeListener> = Topic.create("Note
|
||||
|
||||
@FunctionalInterface
|
||||
interface NotebookEditorModeListener {
|
||||
|
||||
fun onModeChange(editor: Editor, mode: NotebookEditorMode)
|
||||
}
|
||||
|
||||
@@ -150,7 +149,6 @@ fun Editor.setMode(mode: NotebookEditorMode) {
|
||||
}
|
||||
}
|
||||
|
||||
private val INVISIBLE_CARET = CaretVisualAttributes(
|
||||
Color(0, 0, 0, 0),
|
||||
CaretVisualAttributes.Weight.NORMAL)
|
||||
private val INVISIBLE_CARET = CaretVisualAttributes(Gray.TRANSPARENT,
|
||||
CaretVisualAttributes.Weight.NORMAL)
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package com.intellij.notebooks.visualization
|
||||
|
||||
import com.intellij.ide.ui.LafManagerListener
|
||||
import com.intellij.notebooks.ui.editor.actions.command.mode.NOTEBOOK_EDITOR_MODE
|
||||
import com.intellij.notebooks.ui.editor.actions.command.mode.NotebookEditorMode
|
||||
import com.intellij.notebooks.ui.editor.actions.command.mode.NotebookEditorModeListener
|
||||
import com.intellij.notebooks.ui.isFoldingEnabledKey
|
||||
import com.intellij.notebooks.visualization.inlay.JupyterBoundsChangeHandler
|
||||
import com.intellij.notebooks.visualization.ui.*
|
||||
@@ -39,7 +36,7 @@ class NotebookCellInlayManager private constructor(
|
||||
private val shouldCheckInlayOffsets: Boolean,
|
||||
private val inputFactories: List<NotebookCellInlayController.InputFactory>,
|
||||
private val cellExtensionFactories: List<CellExtensionFactory>,
|
||||
) : Disposable, NotebookIntervalPointerFactory.ChangeListener, NotebookEditorModeListener {
|
||||
) : Disposable, NotebookIntervalPointerFactory.ChangeListener {
|
||||
|
||||
private val notebookCellLines = NotebookCellLines.get(editor)
|
||||
|
||||
@@ -83,19 +80,22 @@ class NotebookCellInlayManager private constructor(
|
||||
val newCtx = UpdateContext(force)
|
||||
updateCtx = newCtx
|
||||
try {
|
||||
JupyterBoundsChangeHandler.get(editor).postponeUpdates()
|
||||
val jupyterBoundsChangeHandler = JupyterBoundsChangeHandler.get(editor)
|
||||
jupyterBoundsChangeHandler.postponeUpdates()
|
||||
val r = keepScrollingPositionWhile(editor) {
|
||||
val r = block(newCtx)
|
||||
updateCtx = null
|
||||
if (editorIsProcessingDocument) {
|
||||
postponedUpdates.add(newCtx)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
newCtx.applyUpdates(editor)
|
||||
}
|
||||
r
|
||||
}
|
||||
inlaysChanged()
|
||||
JupyterBoundsChangeHandler.get(editor).performPostponed()
|
||||
jupyterBoundsChangeHandler.boundsChanged()
|
||||
jupyterBoundsChangeHandler.performPostponed()
|
||||
r
|
||||
}
|
||||
finally {
|
||||
@@ -184,8 +184,6 @@ class NotebookCellInlayManager private constructor(
|
||||
setupFoldingListener()
|
||||
setupSelectionUI()
|
||||
|
||||
ApplicationManager.getApplication().messageBus.connect(this).subscribe(NOTEBOOK_EDITOR_MODE, this)
|
||||
|
||||
cellEventListeners.addListener(object : EditorCellEventListener {
|
||||
override fun onEditorCellEvents(events: List<EditorCellEvent>) {
|
||||
updateUI(events)
|
||||
@@ -233,7 +231,6 @@ class NotebookCellInlayManager private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun createCellViewIfNecessary(cell: EditorCell, ctx: UpdateContext) {
|
||||
if (views[cell] == null) {
|
||||
createCellView(cell, ctx)
|
||||
@@ -502,28 +499,6 @@ class NotebookCellInlayManager private constructor(
|
||||
internal fun getInputFactories(): Sequence<NotebookCellInlayController.InputFactory> {
|
||||
return inputFactories.asSequence()
|
||||
}
|
||||
|
||||
override fun onModeChange(editor: Editor, mode: NotebookEditorMode) {
|
||||
if (editor == this.editor) {
|
||||
when (mode) {
|
||||
NotebookEditorMode.EDIT -> {
|
||||
editor.caretModel.allCarets.forEach { caret ->
|
||||
getCellByLine(editor.document.getLineNumber(caret.offset))?.switchToEditMode()
|
||||
}
|
||||
}
|
||||
NotebookEditorMode.COMMAND -> {
|
||||
_cells.forEach {
|
||||
it.switchToCommandMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getCellByLine(line: Int): EditorCell? {
|
||||
return _cells.firstOrNull { it.interval.lines.contains(line) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UpdateContext(val force: Boolean = false) {
|
||||
|
||||
@@ -15,6 +15,18 @@ import com.intellij.openapi.util.Key
|
||||
import com.intellij.util.EventDispatcher
|
||||
import java.beans.PropertyChangeListener
|
||||
|
||||
/**
|
||||
* Per-editor service on which can one subscribe.
|
||||
* It sends the boundsChanged event to the subscribed JupyterBoundsChangeListener.
|
||||
*
|
||||
* boundsChanged event will be dispatched if
|
||||
* - someone directly calls JupyterBoundsChangeHandler.get(editor).boundsChanged()
|
||||
* - EditorImpl property was changed
|
||||
* - On soft wrap recalculation ends
|
||||
* - Folding model change
|
||||
* - Inlay model change
|
||||
*/
|
||||
// Class name does not reflect the functionality of this class.
|
||||
class JupyterBoundsChangeHandler(val editor: EditorImpl) : Disposable {
|
||||
private var isDelayed = false
|
||||
private var isShouldBeRecalculated = false
|
||||
@@ -26,10 +38,8 @@ class JupyterBoundsChangeHandler(val editor: EditorImpl) : Disposable {
|
||||
boundsChanged()
|
||||
}, this)
|
||||
|
||||
|
||||
editor.softWrapModel.addSoftWrapChangeListener(object : SoftWrapChangeListener {
|
||||
override fun softWrapsChanged() {
|
||||
}
|
||||
override fun softWrapsChanged() = Unit
|
||||
|
||||
override fun recalculationEnds() {
|
||||
if (editor.document.isInEventsHandling)
|
||||
@@ -81,7 +91,7 @@ class JupyterBoundsChangeHandler(val editor: EditorImpl) : Disposable {
|
||||
}, this)
|
||||
}
|
||||
|
||||
override fun dispose() {}
|
||||
override fun dispose() = Unit
|
||||
|
||||
fun subscribe(listener: JupyterBoundsChangeListener) {
|
||||
dispatcher.addListener(listener)
|
||||
@@ -91,13 +101,14 @@ class JupyterBoundsChangeHandler(val editor: EditorImpl) : Disposable {
|
||||
dispatcher.removeListener(listener)
|
||||
}
|
||||
|
||||
|
||||
fun boundsChanged() {
|
||||
if (isDelayed) {
|
||||
isShouldBeRecalculated = true
|
||||
return
|
||||
}
|
||||
dispatcher.multicaster.boundsChanged()
|
||||
if (!editor.isDisposed) {
|
||||
dispatcher.multicaster.boundsChanged()
|
||||
}
|
||||
}
|
||||
|
||||
fun postponeUpdates() {
|
||||
@@ -116,7 +127,8 @@ class JupyterBoundsChangeHandler(val editor: EditorImpl) : Disposable {
|
||||
private val INSTANCE_KEY = Key<JupyterBoundsChangeHandler>("INLAYS_CHANGE_HANDLER")
|
||||
|
||||
fun install(editor: EditorImpl) {
|
||||
val updater = JupyterBoundsChangeHandler(editor).also { Disposer.register(editor.disposable, it) }
|
||||
val updater = JupyterBoundsChangeHandler(editor)
|
||||
Disposer.register(editor.disposable, updater)
|
||||
editor.putUserData(INSTANCE_KEY, updater)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,6 @@ package com.intellij.notebooks.visualization.inlay
|
||||
|
||||
import java.util.*
|
||||
|
||||
interface JupyterBoundsChangeListener: EventListener {
|
||||
fun boundsChanged() {}
|
||||
interface JupyterBoundsChangeListener : EventListener {
|
||||
fun boundsChanged() = Unit
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.intellij.notebooks.visualization.ui
|
||||
|
||||
import com.intellij.notebooks.ui.editor.actions.command.mode.NotebookEditorMode
|
||||
import com.intellij.notebooks.visualization.NotebookCellInlayController
|
||||
import com.intellij.notebooks.visualization.NotebookCellInlayManager
|
||||
import com.intellij.notebooks.visualization.NotebookIntervalPointer
|
||||
@@ -44,15 +43,8 @@ class EditorCell(
|
||||
|
||||
val executionStatus = AtomicProperty<ExecutionStatus>(ExecutionStatus())
|
||||
|
||||
// ToDo we should remove or rework this. Mode does not really reflects the state of markdown cells.
|
||||
val mode = AtomicProperty<NotebookEditorMode>(NotebookEditorMode.COMMAND)
|
||||
|
||||
val outputs = AtomicProperty<List<NotebookOutputDataKey>>(getOutputs())
|
||||
|
||||
init {
|
||||
CELL_EXTENSION_CONTAINER_KEY.set(this, mutableMapOf())
|
||||
}
|
||||
|
||||
private fun getSource(): String {
|
||||
val document = editor.document
|
||||
if (interval.lines.first + 1 >= document.lineCount) return ""
|
||||
@@ -151,29 +143,27 @@ class EditorCell(
|
||||
}
|
||||
}
|
||||
|
||||
fun switchToEditMode() = runInEdt {
|
||||
mode.set(NotebookEditorMode.EDIT)
|
||||
}
|
||||
|
||||
fun switchToCommandMode() = runInEdt {
|
||||
mode.set(NotebookEditorMode.COMMAND)
|
||||
}
|
||||
|
||||
fun requestCaret() {
|
||||
view?.requestCaret()
|
||||
}
|
||||
|
||||
inline fun <reified T : EditorCellExtension> getExtension(): T {
|
||||
inline fun <reified T : EditorCellExtension> getExtension(): T? {
|
||||
return getExtension(T::class)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : EditorCellExtension> getExtension(cls: KClass<T>): T {
|
||||
return CELL_EXTENSION_CONTAINER_KEY.get(this)!![cls] as T
|
||||
fun <T : EditorCellExtension> getExtension(cls: KClass<T>): T? {
|
||||
val extensions = CELL_EXTENSION_CONTAINER_KEY.get(this) ?: return null
|
||||
return extensions[cls] as? T
|
||||
}
|
||||
|
||||
fun <T : EditorCellExtension> addExtension(cls: KClass<T>, extension: T) {
|
||||
CELL_EXTENSION_CONTAINER_KEY.get(this)!![cls] = extension
|
||||
var map = CELL_EXTENSION_CONTAINER_KEY.get(this)
|
||||
if (map == null) {
|
||||
map = mutableMapOf<KClass<*>, EditorCellExtension>()
|
||||
CELL_EXTENSION_CONTAINER_KEY.set(this, map)
|
||||
}
|
||||
map[cls] = extension
|
||||
}
|
||||
|
||||
fun onBeforeRemove() {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.intellij.notebooks.visualization.ui
|
||||
|
||||
interface EditorCellExtension {
|
||||
|
||||
fun onBeforeRemove() {}
|
||||
|
||||
fun onBeforeRemove() = Unit
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.intellij.notebooks.visualization.ui
|
||||
|
||||
import com.intellij.openapi.editor.impl.EditorImpl
|
||||
import com.intellij.ui.ExperimentalUI
|
||||
import com.intellij.ui.paint.LinePainter2D
|
||||
import com.intellij.ui.paint.RectanglePainter2D
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import com.intellij.notebooks.ui.visualization.NotebookEditorAppearanceUtils.isOrdinaryNotebookEditor
|
||||
import com.intellij.notebooks.ui.visualization.notebookAppearance
|
||||
import com.intellij.notebooks.visualization.inlay.JupyterBoundsChangeHandler
|
||||
import com.intellij.notebooks.visualization.inlay.JupyterBoundsChangeListener
|
||||
import com.intellij.notebooks.visualization.use
|
||||
import com.intellij.openapi.editor.impl.EditorImpl
|
||||
import com.intellij.ui.ExperimentalUI
|
||||
import com.intellij.ui.paint.LinePainter2D
|
||||
import com.intellij.ui.paint.RectanglePainter2D
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.awt.*
|
||||
import java.awt.event.MouseAdapter
|
||||
import java.awt.event.MouseEvent
|
||||
@@ -75,7 +75,9 @@ class EditorCellFoldingBar(
|
||||
panel.setBounds(editor.gutterComponentEx.extraLineMarkerFreePaintersAreaOffset + 1, yAndHeight.first, 6, yAndHeight.second)
|
||||
}
|
||||
|
||||
private fun createFoldingBar() = object : JComponent() {
|
||||
private fun createFoldingBar() = EditorCellFoldingBarComponent()
|
||||
|
||||
inner class EditorCellFoldingBarComponent : JComponent() {
|
||||
private var mouseOver = false
|
||||
|
||||
init {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.intellij.notebooks.visualization.ui
|
||||
|
||||
import com.intellij.codeInsight.hints.presentation.InlayPresentation
|
||||
import com.intellij.notebooks.visualization.UpdateContext
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.editor.Inlay
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.notebooks.visualization.UpdateContext
|
||||
import java.awt.Rectangle
|
||||
import java.util.Collections
|
||||
import java.util.*
|
||||
|
||||
abstract class EditorCellViewComponent : Disposable {
|
||||
protected var parent: EditorCellViewComponent? = null
|
||||
@@ -23,7 +23,7 @@ abstract class EditorCellViewComponent : Disposable {
|
||||
Disposer.register(this, child)
|
||||
}
|
||||
|
||||
/* Chile disposable will be automatically disposed. */
|
||||
/* Child will be automatically disposed. */
|
||||
fun remove(child: EditorCellViewComponent) {
|
||||
Disposer.dispose(child)
|
||||
_children.remove(child)
|
||||
|
||||
@@ -43,7 +43,6 @@ class TextEditorCellViewComponent(
|
||||
override fun mousePressed(e: MouseEvent) {
|
||||
if (editor.xyToLogicalPosition(e.point).line in cell.interval.lines) {
|
||||
editor.setMode(NotebookEditorMode.EDIT)
|
||||
cell.switchToEditMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,21 +59,21 @@ class TextEditorCellViewComponent(
|
||||
|
||||
private fun updateGutterIcons(gutterAction: AnAction?) = runInEdt {
|
||||
disposeExistingHighlighter()
|
||||
if (gutterAction != null) {
|
||||
val markupModel = editor.markupModel
|
||||
val interval = safeInterval ?: return@runInEdt
|
||||
val startOffset = editor.document.getLineStartOffset(interval.lines.first)
|
||||
val endOffset = editor.document.getLineEndOffset(interval.lines.last)
|
||||
val highlighter = markupModel.addRangeHighlighter(
|
||||
startOffset,
|
||||
endOffset,
|
||||
HighlighterLayer.FIRST - 100,
|
||||
TextAttributes(),
|
||||
HighlighterTargetArea.LINES_IN_RANGE
|
||||
)
|
||||
highlighter.gutterIconRenderer = ActionToGutterRendererAdapter(gutterAction)
|
||||
this.highlighters = listOf(highlighter)
|
||||
}
|
||||
if (gutterAction == null) return@runInEdt
|
||||
|
||||
val markupModel = editor.markupModel
|
||||
val interval = safeInterval ?: return@runInEdt
|
||||
val startOffset = editor.document.getLineStartOffset(interval.lines.first)
|
||||
val endOffset = editor.document.getLineEndOffset(interval.lines.last)
|
||||
val highlighter = markupModel.addRangeHighlighter(
|
||||
startOffset,
|
||||
endOffset,
|
||||
HighlighterLayer.FIRST - 100,
|
||||
TextAttributes(),
|
||||
HighlighterTargetArea.LINES_IN_RANGE
|
||||
)
|
||||
highlighter.gutterIconRenderer = ActionToGutterRendererAdapter(gutterAction)
|
||||
this.highlighters = listOf(highlighter)
|
||||
}
|
||||
|
||||
override fun dispose() = cell.manager.update { ctx ->
|
||||
|
||||
Reference in New Issue
Block a user