mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-CR-55846 UX-931 intentions preview: corrections by review
Use `coalesceBy` and `finishOnUiThread` API for preview updating; better kotlin way coding GitOrigin-RevId: 061d726108500c77300f6bd73c52c634de1d3faa
This commit is contained in:
committed by
intellij-monorepo-bot
parent
2396f2de00
commit
bf05d33d14
+1
-3
@@ -42,7 +42,6 @@ import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.psi.stubs.StubTextInconsistencyException;
|
||||
import com.intellij.util.PairProcessor;
|
||||
import com.intellij.util.ThreeState;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -227,8 +226,7 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static void invokeIntention(@NotNull IntentionAction action, @Nullable Editor editor, @NotNull PsiFile file) {
|
||||
private static void invokeIntention(@NotNull IntentionAction action, @Nullable Editor editor, @NotNull PsiFile file) {
|
||||
IntentionsCollector.getInstance().record(file.getProject(), action, file.getLanguage());
|
||||
PsiElement elementToMakeWritable = action.getElementToMakeWritable(file);
|
||||
if (elementToMakeWritable != null && !FileModificationService.getInstance().preparePsiElementsForWrite(elementToMakeWritable)) {
|
||||
|
||||
+8
-6
@@ -23,16 +23,16 @@ import java.util.concurrent.Callable
|
||||
internal class IntentionPreviewComputable(private val project: Project,
|
||||
private val action: IntentionAction,
|
||||
private val originalFile: PsiFile,
|
||||
private val originalEditor: Editor) : Callable<Pair<PsiFile?, List<LineFragment>>> {
|
||||
override fun call(): Pair<PsiFile?, List<LineFragment>> {
|
||||
private val originalEditor: Editor) : Callable<IntentionPreviewResult?> {
|
||||
override fun call(): IntentionPreviewResult? {
|
||||
val psiFileCopy = nonPhysicalPsiCopy(originalFile, project)
|
||||
ProgressManager.checkCanceled()
|
||||
val editorCopy = IntentionPreviewEditor(psiFileCopy, originalEditor.caretModel.offset)
|
||||
|
||||
try {
|
||||
val action = findCopyIntention(project, editorCopy, psiFileCopy, action) ?: throw ProcessCanceledException()
|
||||
val action = findCopyIntention(project, editorCopy, psiFileCopy, action) ?: return null
|
||||
val fileEditorPair = ShowIntentionActionsHandler.chooseFileForAction(psiFileCopy, editorCopy, action)
|
||||
?: throw ProcessCanceledException()
|
||||
?: return null
|
||||
|
||||
val writable = originalEditor.document.isWritable
|
||||
try {
|
||||
@@ -45,7 +45,7 @@ internal class IntentionPreviewComputable(private val project: Project,
|
||||
originalEditor.document.setReadOnly(!writable)
|
||||
}
|
||||
|
||||
return Pair<PsiFile?, List<LineFragment>>(
|
||||
return IntentionPreviewResult(
|
||||
psiFileCopy,
|
||||
ComparisonManager.getInstance().compareLines(originalFile.text, editorCopy.document.text, ComparisonPolicy.TRIM_WHITESPACES,
|
||||
DumbProgressIndicator.INSTANCE)
|
||||
@@ -87,4 +87,6 @@ internal class IntentionPreviewComputable(private val project: Project,
|
||||
return getFixes(cachedIntentions).find { it.text == originalAction.text }?.action
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class IntentionPreviewResult(val psiFile: PsiFile?, val lineFragments: List<LineFragment>)
|
||||
+1
-3
@@ -22,9 +22,7 @@ internal class IntentionPreviewEditorsPanel(val editors: List<EditorEx>) : JPane
|
||||
|
||||
private fun createSeparatorLine(colorsScheme: EditorColorsScheme): JPanel {
|
||||
var color = colorsScheme.getColor(CodeInsightColors.METHOD_SEPARATORS_COLOR)
|
||||
if (color == null) {
|
||||
color = JBColor.namedColor("Group.separatorColor", JBColor(Gray.xCD, Gray.x51))
|
||||
}
|
||||
color = color?.let { JBColor.namedColor("Group.separatorColor", JBColor(Gray.xCD, Gray.x51)) }
|
||||
|
||||
return JBUI.Panels.simplePanel().withBorder(JBUI.Borders.customLine(color, 1, 0, 0, 0))
|
||||
}
|
||||
|
||||
+9
-5
@@ -9,6 +9,7 @@ import com.intellij.ui.components.panels.NonOpaquePanel
|
||||
import com.intellij.ui.components.panels.OpaquePanel
|
||||
import com.intellij.util.ui.AsyncProcessIcon
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Color
|
||||
import java.awt.FlowLayout
|
||||
import javax.swing.JLabel
|
||||
import javax.swing.JPanel
|
||||
@@ -16,17 +17,18 @@ import javax.swing.JPanel
|
||||
internal class IntentionPreviewLoadingDecorator(panel: JPanel, project: Project) :
|
||||
LoadingDecorator(panel, project, 500, false, AsyncProcessIcon("IntentionPreviewProcessLoading")) {
|
||||
override fun customizeLoadingLayer(parent: JPanel, text: JLabel, icon: AsyncProcessIcon): NonOpaquePanel {
|
||||
val editorBackground = EditorColorsManager.getInstance().globalScheme.defaultBackground
|
||||
val iconNonOpaquePanel = OpaquePanel(FlowLayout(FlowLayout.RIGHT, 2, 2))
|
||||
.also {
|
||||
it.add(icon, BorderLayout.NORTH)
|
||||
it.background = EditorColorsManager.getInstance().globalScheme.defaultBackground
|
||||
.apply {
|
||||
add(icon, BorderLayout.NORTH)
|
||||
background = editorBackground
|
||||
}
|
||||
|
||||
icon.background = ColorUtil.withAlpha(EditorColorsManager.getInstance().globalScheme.defaultBackground, 0.0)
|
||||
icon.background = editorBackground.withAlpha(0.0)
|
||||
icon.isOpaque = true
|
||||
|
||||
val opaquePanel = OpaquePanel()
|
||||
opaquePanel.background = ColorUtil.withAlpha(EditorColorsManager.getInstance().globalScheme.defaultBackground, 0.6)
|
||||
opaquePanel.background = editorBackground.withAlpha(0.6)
|
||||
|
||||
val nonOpaquePanel = NonOpaquePanel(BorderLayout())
|
||||
nonOpaquePanel.add(iconNonOpaquePanel, BorderLayout.EAST)
|
||||
@@ -37,4 +39,6 @@ internal class IntentionPreviewLoadingDecorator(panel: JPanel, project: Project)
|
||||
|
||||
return nonOpaquePanel
|
||||
}
|
||||
|
||||
fun Color.withAlpha(alpha: Double) = ColorUtil.withAlpha(this, alpha)
|
||||
}
|
||||
+8
-8
@@ -33,11 +33,11 @@ internal class IntentionPreviewModel {
|
||||
})
|
||||
}
|
||||
|
||||
fun createEditors(project: Project, originalFile: PsiFile, pair: Pair<PsiFile?, List<LineFragment>>?): List<EditorEx> {
|
||||
if (pair == null) return emptyList()
|
||||
fun createEditors(project: Project, originalFile: PsiFile, result: IntentionPreviewResult?): List<EditorEx> {
|
||||
if (result == null) return emptyList()
|
||||
|
||||
val psiFileCopy: PsiFile? = pair.first
|
||||
val lines: List<LineFragment> = pair.second
|
||||
val psiFileCopy: PsiFile? = result.psiFile
|
||||
val lines: List<LineFragment> = result.lineFragments
|
||||
|
||||
if (psiFileCopy == null) return emptyList()
|
||||
|
||||
@@ -64,7 +64,7 @@ internal class IntentionPreviewModel {
|
||||
val editorFactory = EditorFactory.getInstance()
|
||||
val document = editorFactory.createDocument(text)
|
||||
val editor = (editorFactory.createEditor(document, project, fileType, false) as EditorEx)
|
||||
.also { it.setBorder(JBUI.Borders.empty(2, 0, 2, 0)) }
|
||||
.apply { setBorder(JBUI.Borders.empty(2, 0, 2, 0)) }
|
||||
|
||||
editor.settings.apply {
|
||||
isLineNumbersShown = true
|
||||
@@ -78,9 +78,9 @@ internal class IntentionPreviewModel {
|
||||
isAdditionalPageAtBottom = false
|
||||
}
|
||||
|
||||
editor.gutterComponentEx.also {
|
||||
it.setPaintBackground(false)
|
||||
it.setLineNumberConvertor { line -> line + lineShift }
|
||||
editor.gutterComponentEx.apply {
|
||||
setPaintBackground(false)
|
||||
setLineNumberConvertor { line -> line + lineShift }
|
||||
}
|
||||
|
||||
return editor
|
||||
|
||||
+31
-52
@@ -6,8 +6,8 @@ import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.codeInsight.intention.impl.IntentionHintComponent
|
||||
import com.intellij.codeInsight.intention.impl.preview.IntentionPreviewComponent.Companion.LOADING_PREVIEW
|
||||
import com.intellij.codeInsight.intention.impl.preview.IntentionPreviewComponent.Companion.NO_PREVIEW
|
||||
import com.intellij.diff.fragments.LineFragment
|
||||
import com.intellij.openapi.actionSystem.CommonShortcuts.ESCAPE
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.application.ReadAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
@@ -19,28 +19,22 @@ import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.ui.popup.PopupPositionManager
|
||||
import com.intellij.ui.popup.PopupUpdateProcessor
|
||||
import com.intellij.util.Alarm
|
||||
import com.intellij.util.concurrency.AppExecutorUtil
|
||||
import org.jetbrains.concurrency.CancellablePromise
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
internal class IntentionPreviewPopupUpdateProcessor(private val project: Project,
|
||||
private val originalFile: PsiFile,
|
||||
private val originalEditor: Editor) : PopupUpdateProcessor(project) {
|
||||
private var index: Int = LOADING_PREVIEW
|
||||
private var show = false
|
||||
private val alarm = Alarm()
|
||||
private val editorsToRelease = mutableListOf<EditorEx>()
|
||||
|
||||
private lateinit var popup: JBPopup
|
||||
private lateinit var component: IntentionPreviewComponent
|
||||
private lateinit var updateAdvText: (String) -> Unit
|
||||
|
||||
private var editorsToRelease = mutableListOf<EditorEx>()
|
||||
private lateinit var updateAdvertiserText: (String) -> Unit
|
||||
|
||||
override fun updatePopup(intentionAction: Any?) {
|
||||
if (!show) return
|
||||
|
||||
alarm.cancelAllRequests()
|
||||
if (!::popup.isInitialized || popup.isDisposed) {
|
||||
component = IntentionPreviewComponent(project)
|
||||
component.multiPanel.select(LOADING_PREVIEW, true)
|
||||
@@ -51,7 +45,7 @@ internal class IntentionPreviewPopupUpdateProcessor(private val project: Project
|
||||
|
||||
PopupPositionManager.positionPopupInBestPosition(popup, originalEditor, null)
|
||||
|
||||
updateAdvText.invoke(CodeInsightBundle.message("intention.preview.adv.hide.text", Companion.ESCAPE_SHORTCUT_TEXT))
|
||||
updateAdvertiserText.invoke(CodeInsightBundle.message("intention.preview.adv.hide.text", ESCAPE_SHORTCUT_TEXT))
|
||||
}
|
||||
|
||||
val value = component.multiPanel.getValue(index, false)
|
||||
@@ -66,62 +60,47 @@ internal class IntentionPreviewPopupUpdateProcessor(private val project: Project
|
||||
return
|
||||
}
|
||||
|
||||
UpdatePopup(project, action, originalFile, originalEditor).start()
|
||||
component.startLoading()
|
||||
|
||||
ReadAction.nonBlocking(
|
||||
IntentionPreviewComputable(project, action, originalFile, originalEditor))
|
||||
.expireWith(popup)
|
||||
.coalesceBy(this)
|
||||
.finishOnUiThread(ModalityState.defaultModalityState()) { renderPreview(it)}
|
||||
.submit(AppExecutorUtil.getAppExecutorService())
|
||||
}
|
||||
|
||||
fun setup(updateAdvConsumer: (String) -> Unit, parentIndex: Int) {
|
||||
private fun renderPreview(result: IntentionPreviewResult?) {
|
||||
try {
|
||||
val editors = IntentionPreviewModel.createEditors(project, originalFile, result)
|
||||
if (editors.isEmpty()) {
|
||||
select(NO_PREVIEW)
|
||||
return
|
||||
}
|
||||
|
||||
editorsToRelease.addAll(editors)
|
||||
select(index, editors)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
select(NO_PREVIEW)
|
||||
}
|
||||
}
|
||||
|
||||
fun setup(updateAdvertiser: (String) -> Unit, parentIndex: Int) {
|
||||
index = parentIndex
|
||||
updateAdvText = updateAdvConsumer
|
||||
updateAdvertiserText = updateAdvertiser
|
||||
}
|
||||
|
||||
private fun cancel(): Boolean {
|
||||
editorsToRelease.forEach { EditorFactory.getInstance().releaseEditor(it) }
|
||||
editorsToRelease.clear()
|
||||
component.removeAll()
|
||||
alarm.cancelAllRequests()
|
||||
show = false
|
||||
updateAdvText.invoke(
|
||||
updateAdvertiserText.invoke(
|
||||
CodeInsightBundle.message("intention.preview.adv.show.text", IntentionHintComponent.INTENTION_PREVIEW_SHORTCUT_TEXT))
|
||||
return true
|
||||
}
|
||||
|
||||
inner class UpdatePopup(private val project: Project,
|
||||
private val action: IntentionAction,
|
||||
private val originalFile: PsiFile,
|
||||
private val originalEditor: Editor) : Runnable {
|
||||
lateinit var computation: CancellablePromise<Pair<PsiFile?, List<LineFragment>>?>
|
||||
|
||||
fun start() {
|
||||
component.startLoading()
|
||||
|
||||
computation = ReadAction.nonBlocking<Pair<PsiFile?, List<LineFragment>>>(
|
||||
IntentionPreviewComputable(project, action, originalFile, originalEditor)).submit(AppExecutorUtil.getAppExecutorService())
|
||||
|
||||
alarm.addRequest(this, 100)
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
if (!computation.isCancelled && !computation.isDone) {
|
||||
alarm.addRequest(this, 200)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
val editors = IntentionPreviewModel.createEditors(project, originalFile, computation.get(3, TimeUnit.SECONDS))
|
||||
if (editors.isEmpty()) {
|
||||
select(NO_PREVIEW)
|
||||
return
|
||||
}
|
||||
|
||||
editorsToRelease.addAll(editors)
|
||||
select(index, editors)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
select(NO_PREVIEW)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleShow() {
|
||||
show = !show
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user