From 2396f2de0070fb3be2c3d660ab143ee1885f4dce Mon Sep 17 00:00:00 2001 From: "Dmitry.Krasilschikov" Date: Wed, 27 Nov 2019 22:35:52 +0200 Subject: [PATCH] IDEA-CR-55846 UX-931 intentions preview: corrections by review GitOrigin-RevId: b3d846559e37f2012906a7e2cfa91da1a5a0fd01 --- .../daemon/impl/ShowIntentionsPass.java | 3 +- .../impl/IntentionHintComponent.java | 9 +- .../impl/ShowIntentionActionsHandler.java | 7 +- .../impl/preview/IntentionPreviewComponent.kt | 4 +- .../preview/IntentionPreviewComputable.kt | 100 ++++++----- .../impl/preview/IntentionPreviewEditor.kt | 156 +++++++++--------- .../preview/IntentionPreviewEditorsPanel.kt | 2 +- .../IntentionPreviewLoadingDecorator.kt | 2 +- .../impl/preview/IntentionPreviewModel.kt | 22 +-- .../IntentionPreviewPopupUpdateProcessor.kt | 49 +++--- .../src/messages/CodeInsightBundle.properties | 2 +- 11 files changed, 171 insertions(+), 185 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java index 8e9f8b3bf809..5d7b615376dd 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java @@ -10,6 +10,7 @@ import com.intellij.codeInsight.intention.impl.CachedIntentions; import com.intellij.codeInsight.intention.impl.EditIntentionSettingsAction; import com.intellij.codeInsight.intention.impl.EnableDisableIntentionAction; import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler; +import com.intellij.codeInsight.intention.impl.preview.IntentionPreviewUnsupportedOperationException; import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.lang.annotation.HighlightSeverity; @@ -335,7 +336,7 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass { try { extension.collectActions(hostEditor, hostFile, intentions, passIdToShowIntentionsFor, offset); } - catch (UnsupportedOperationException e) { + catch (IntentionPreviewUnsupportedOperationException e) { //can collect action on a mock memory editor and produce exceptions - ignore } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionHintComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionHintComponent.java index a57142e7729c..420a070c214b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionHintComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionHintComponent.java @@ -80,8 +80,9 @@ public class IntentionHintComponent implements Disposable, ScrollAwareHint { private static final Border INACTIVE_BORDER = BorderFactory.createEmptyBorder(NORMAL_BORDER_SIZE, NORMAL_BORDER_SIZE, NORMAL_BORDER_SIZE, NORMAL_BORDER_SIZE); private static final Border INACTIVE_BORDER_SMALL = BorderFactory.createEmptyBorder(SMALL_BORDER_SIZE, SMALL_BORDER_SIZE, SMALL_BORDER_SIZE, SMALL_BORDER_SIZE); - public static final KeyboardShortcut ALT_SPACE_SHORTCUT = KeyboardShortcut.fromString(("alt SPACE")); - public static final String ALT_SPACE_SHORTCUT_TEXT = KeymapUtil.getShortcutText(ALT_SPACE_SHORTCUT); + + private static final ShortcutSet INTENTION_PREVIEW_SHORTCUT_SET = KeymapUtil.getActiveKeymapShortcuts(IdeActions.ACTION_QUICK_IMPLEMENTATIONS); + public static final String INTENTION_PREVIEW_SHORTCUT_TEXT = KeymapUtil.getPreferredShortcutText(INTENTION_PREVIEW_SHORTCUT_SET.getShortcuts()); private final IntentionPreviewPopupUpdateProcessor myPreviewPopupUpdateProcessor; @TestOnly @@ -524,7 +525,7 @@ public class IntentionHintComponent implements Disposable, ScrollAwareHint { } private void registerShowPreviewAction() { - ((WizardPopup)myPopup).registerAction("showIntentionPreview", ALT_SPACE_SHORTCUT.getFirstKeyStroke(), new AbstractAction() { + ((WizardPopup)myPopup).registerAction("showIntentionPreview", KeymapUtil.getKeyStroke(INTENTION_PREVIEW_SHORTCUT_SET), new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { myPreviewPopupUpdateProcessor.toggleShow(); @@ -538,7 +539,7 @@ public class IntentionHintComponent implements Disposable, ScrollAwareHint { } } }); - myPopup.setAdText(CodeInsightBundle.message("intention.preview.adv.show.text", ALT_SPACE_SHORTCUT_TEXT), SwingConstants.LEFT); + myPopup.setAdText(CodeInsightBundle.message("intention.preview.adv.show.text", INTENTION_PREVIEW_SHORTCUT_TEXT), SwingConstants.LEFT); } void canceled(@NotNull ListPopupStep intentionListStep) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java index 004b228f3f9f..05d1988b2a7e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java @@ -13,6 +13,7 @@ import com.intellij.codeInsight.hint.HintManagerImpl; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.IntentionActionDelegate; import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.codeInsight.intention.impl.preview.IntentionPreviewUnsupportedOperationException; import com.intellij.codeInsight.lookup.LookupEx; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.template.impl.TemplateManagerImpl; @@ -41,6 +42,7 @@ 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; @@ -150,7 +152,7 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler { catch (IndexNotReadyException e) { return false; } - catch (Exception e) { + catch (IntentionPreviewUnsupportedOperationException e) { //check action availability can be invoked on a mock editor and may produce exceptions return false; } @@ -182,7 +184,7 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler { if (editorToApply == null) return null; return Pair.create(fileToApply, editorToApply); } - catch (UnsupportedOperationException e) { + catch (IntentionPreviewUnsupportedOperationException e) { return null; } } @@ -225,6 +227,7 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler { } } + @ApiStatus.Internal public 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); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewComponent.kt b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewComponent.kt index bcf986d64b5d..5ad7a5608631 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewComponent.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewComponent.kt @@ -14,8 +14,8 @@ import javax.swing.JComponent import javax.swing.JLabel import javax.swing.JPanel -class IntentionPreviewComponent(project: Project) : JBLoadingPanel(BorderLayout(), - { panel -> IntentionPreviewLoadingDecorator(panel, project) }) { +internal class IntentionPreviewComponent(project: Project) : JBLoadingPanel(BorderLayout(), + { panel -> IntentionPreviewLoadingDecorator(panel, project) }) { private var NO_PREVIEW_LABEL = JLabel(CodeInsightBundle.message("intention.preview.no.available.text") + " ").also { setupLabel(it) } private var LOADING_LABEL = JLabel(CodeInsightBundle.message("intention.preview.loading.preview") + " ").also { setupLabel(it) } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewComputable.kt b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewComputable.kt index 1e9148b33f8d..d78d4b0ef61d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewComputable.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewComputable.kt @@ -9,73 +9,55 @@ import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler import com.intellij.diff.comparison.ComparisonManager import com.intellij.diff.comparison.ComparisonPolicy import com.intellij.diff.fragments.LineFragment -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.runReadAction import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.editor.Editor import com.intellij.openapi.progress.DumbProgressIndicator import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.Project -import com.intellij.openapi.util.Computable -import com.intellij.openapi.util.ThrowableComputable -import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiFile import com.intellij.psi.PsiFileFactory +import java.util.concurrent.Callable -class IntentionPreviewComputable(private val project: Project, - private val action: IntentionAction, - private val originalFile: PsiFile, - private val originalEditor: Editor) : Computable>?> { - override fun compute(): Pair>? { - val psiFileCopy = runReadAction { nonPhysicalPsiCopy(originalFile, project) } + +internal class IntentionPreviewComputable(private val project: Project, + private val action: IntentionAction, + private val originalFile: PsiFile, + private val originalEditor: Editor) : Callable>> { + override fun call(): Pair> { + val psiFileCopy = nonPhysicalPsiCopy(originalFile, project) ProgressManager.checkCanceled() - - val editorCopy = try { - IntentionPreviewEditor(psiFileCopy, runReadAction { originalEditor.caretModel.offset }) - } - catch (e: IllegalStateException) { - LOG.warn(e) - throw ProcessCanceledException() - } + val editorCopy = IntentionPreviewEditor(psiFileCopy, originalEditor.caretModel.offset) try { - ApplicationManager.getApplication().runReadAction(ThrowableComputable { - val action = (intentionActionWithTextCaching(editorCopy, psiFileCopy) ?: return@ThrowableComputable).action - val fileEditorPair = ShowIntentionActionsHandler.chooseFileForAction(psiFileCopy, editorCopy, action) - ?: return@ThrowableComputable + val action = findCopyIntention(project, editorCopy, psiFileCopy, action) ?: throw ProcessCanceledException() + val fileEditorPair = ShowIntentionActionsHandler.chooseFileForAction(psiFileCopy, editorCopy, action) + ?: throw ProcessCanceledException() - try { - originalEditor.document.setReadOnly(true) - ProgressManager.checkCanceled() - action.invoke(project, fileEditorPair.second, fileEditorPair.first) - ProgressManager.checkCanceled() - } - finally { - originalEditor.document.setReadOnly(false) - } - }) + val writable = originalEditor.document.isWritable + try { + originalEditor.document.setReadOnly(true) + ProgressManager.checkCanceled() + action.invoke(project, fileEditorPair.second, fileEditorPair.first) + ProgressManager.checkCanceled() + } + finally { + originalEditor.document.setReadOnly(!writable) + } + + return Pair>( + psiFileCopy, + ComparisonManager.getInstance().compareLines(originalFile.text, editorCopy.document.text, ComparisonPolicy.TRIM_WHITESPACES, + DumbProgressIndicator.INSTANCE) + ) } - catch (e: UnsupportedOperationException) { + catch (e: IntentionPreviewUnsupportedOperationException) { throw ProcessCanceledException() } catch (e: Exception) { LOG.debug("There are exceptions on invocation the intention: '${action.text}' on a copy of the file.", e) - throw ProcessCanceledException() + throw ProcessCanceledException(e) } - - return Pair>( - psiFileCopy, - PsiDocumentManager.getInstance(project).commitAndRunReadAction(Computable { - ComparisonManager.getInstance().compareLines(originalFile.text, psiFileCopy.text, ComparisonPolicy.TRIM_WHITESPACES, - DumbProgressIndicator.INSTANCE) - })) - } - - private fun intentionActionWithTextCaching(editorCopy: Editor, psiFileCopy: PsiFile): IntentionActionWithTextCaching? { - val actionsToShow = ShowIntentionsPass.getActionsToShow(editorCopy, psiFileCopy, false) - val cachedIntentions = CachedIntentions.createAndUpdateActions(project, psiFileCopy, editorCopy, actionsToShow) - return getFixes(cachedIntentions).find { it.text == action.text } } private fun nonPhysicalPsiCopy(psiFile: PsiFile, project: Project): PsiFile { @@ -86,13 +68,23 @@ class IntentionPreviewComputable(private val project: Project, psiFile.virtualFile) } - fun getFixes(cachedIntentions: CachedIntentions): Sequence = - sequenceOf() - .plus(cachedIntentions.intentions) - .plus(cachedIntentions.inspectionFixes) - .plus(cachedIntentions.errorFixes) - companion object { private val LOG = Logger.getInstance(IntentionPreviewComputable::class.java) + + fun getFixes(cachedIntentions: CachedIntentions): Sequence = + sequenceOf() + .plus(cachedIntentions.intentions) + .plus(cachedIntentions.inspectionFixes) + .plus(cachedIntentions.errorFixes) + + private fun findCopyIntention(project: Project, + editorCopy: Editor, + psiFileCopy: PsiFile, + originalAction: IntentionAction): IntentionAction? { + val actionsToShow = ShowIntentionsPass.getActionsToShow(editorCopy, psiFileCopy, false) + val cachedIntentions = CachedIntentions.createAndUpdateActions(project, psiFileCopy, editorCopy, actionsToShow) + + return getFixes(cachedIntentions).find { it.text == originalAction.text }?.action + } } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewEditor.kt b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewEditor.kt index c155a68a7c28..f3f10f8d8759 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewEditor.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewEditor.kt @@ -2,7 +2,6 @@ package com.intellij.codeInsight.intention.impl.preview import com.intellij.openapi.Disposable -import com.intellij.openapi.application.runReadAction import com.intellij.openapi.editor.* import com.intellij.openapi.editor.colors.EditorColorsScheme import com.intellij.openapi.editor.event.CaretListener @@ -22,93 +21,92 @@ import java.awt.geom.Point2D import javax.swing.JComponent import javax.swing.border.Border -class IntentionPreviewEditor(private val psiFileCopy: PsiFile, private var caretOffset: Int) : UserDataHolderBase(), Editor { - private val document: Document = runReadAction { FileDocumentManager.getInstance().getDocument(psiFileCopy.viewProvider.virtualFile) } +internal class IntentionPreviewEditor(private val psiFileCopy: PsiFile, private var caretOffset: Int) : UserDataHolderBase(), Editor { + private val document: Document = FileDocumentManager.getInstance().getDocument(psiFileCopy.viewProvider.virtualFile) ?: throw IllegalStateException("Document should be not null.") - companion object { - const val UNSUPPORTED_MESSAGE: String = "It's unexpected to invoke this method on an intention preview calculating." - } - private val caretModel = IntentionPreviewCaretModel() override fun getDocument(): Document = document override fun getCaretModel() = caretModel - override fun isViewer(): Boolean = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getComponent(): JComponent = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getContentComponent(): JComponent = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun setBorder(border: Border?) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getInsets(): Insets = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getMarkupModel(): MarkupModel = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getScrollingModel(): ScrollingModel = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getSoftWrapModel(): SoftWrapModel = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getSettings(): EditorSettings = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getColorsScheme(): EditorColorsScheme = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getLineHeight(): Int = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun logicalPositionToXY(pos: LogicalPosition): Point = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun logicalPositionToOffset(pos: LogicalPosition): Int = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun logicalToVisualPosition(logicalPos: LogicalPosition): VisualPosition = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun visualPositionToXY(visible: VisualPosition): Point = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun visualPositionToPoint2D(pos: VisualPosition): Point2D = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun visualToLogicalPosition(visiblePos: VisualPosition): LogicalPosition = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun offsetToLogicalPosition(offset: Int): LogicalPosition = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun offsetToVisualPosition(offset: Int): VisualPosition = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun offsetToVisualPosition(offset: Int, leanForward: Boolean, beforeSoftWrap: Boolean): VisualPosition = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getFoldingModel(): FoldingModel = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun xyToLogicalPosition(p: Point): LogicalPosition = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun xyToVisualPosition(p: Point): VisualPosition = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun xyToVisualPosition(p: Point2D): VisualPosition = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun addEditorMouseListener(listener: EditorMouseListener) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun removeEditorMouseListener(listener: EditorMouseListener) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun addEditorMouseMotionListener(listener: EditorMouseMotionListener) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun removeEditorMouseMotionListener(listener: EditorMouseMotionListener) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun isDisposed(): Boolean = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getProject(): Project? = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun isInsertMode(): Boolean = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getSelectionModel(): SelectionModel = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun isColumnMode(): Boolean = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun isOneLineMode(): Boolean = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getGutter(): EditorGutter = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getMouseEventArea(e: MouseEvent): EditorMouseEventArea? = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun setHeaderComponent(header: JComponent?) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun hasHeaderComponent(): Boolean = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getHeaderComponent(): JComponent? = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getIndentsModel(): IndentsModel = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getInlayModel(): InlayModel = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getEditorKind(): EditorKind = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) + override fun isViewer(): Boolean = throw IntentionPreviewUnsupportedOperationException() + override fun getComponent(): JComponent = throw IntentionPreviewUnsupportedOperationException() + override fun getContentComponent(): JComponent = throw IntentionPreviewUnsupportedOperationException() + override fun setBorder(border: Border?) = throw IntentionPreviewUnsupportedOperationException() + override fun getInsets(): Insets = throw IntentionPreviewUnsupportedOperationException() + override fun getMarkupModel(): MarkupModel = throw IntentionPreviewUnsupportedOperationException() + override fun getScrollingModel(): ScrollingModel = throw IntentionPreviewUnsupportedOperationException() + override fun getSoftWrapModel(): SoftWrapModel = throw IntentionPreviewUnsupportedOperationException() + override fun getSettings(): EditorSettings = throw IntentionPreviewUnsupportedOperationException() + override fun getColorsScheme(): EditorColorsScheme = throw IntentionPreviewUnsupportedOperationException() + override fun getLineHeight(): Int = throw IntentionPreviewUnsupportedOperationException() + override fun logicalPositionToXY(pos: LogicalPosition): Point = throw IntentionPreviewUnsupportedOperationException() + override fun logicalPositionToOffset(pos: LogicalPosition): Int = throw IntentionPreviewUnsupportedOperationException() + override fun logicalToVisualPosition(logicalPos: LogicalPosition): VisualPosition = throw IntentionPreviewUnsupportedOperationException() + override fun visualPositionToXY(visible: VisualPosition): Point = throw IntentionPreviewUnsupportedOperationException() + override fun visualPositionToPoint2D(pos: VisualPosition): Point2D = throw IntentionPreviewUnsupportedOperationException() + override fun visualToLogicalPosition(visiblePos: VisualPosition): LogicalPosition = throw IntentionPreviewUnsupportedOperationException() + override fun offsetToLogicalPosition(offset: Int): LogicalPosition = throw IntentionPreviewUnsupportedOperationException() + override fun offsetToVisualPosition(offset: Int): VisualPosition = throw IntentionPreviewUnsupportedOperationException() + override fun offsetToVisualPosition(offset: Int, leanForward: Boolean, beforeSoftWrap: Boolean): VisualPosition = throw IntentionPreviewUnsupportedOperationException() + override fun getFoldingModel(): FoldingModel = throw IntentionPreviewUnsupportedOperationException() + override fun xyToLogicalPosition(p: Point): LogicalPosition = throw IntentionPreviewUnsupportedOperationException() + override fun xyToVisualPosition(p: Point): VisualPosition = throw IntentionPreviewUnsupportedOperationException() + override fun xyToVisualPosition(p: Point2D): VisualPosition = throw IntentionPreviewUnsupportedOperationException() + override fun addEditorMouseListener(listener: EditorMouseListener) = throw IntentionPreviewUnsupportedOperationException() + override fun removeEditorMouseListener(listener: EditorMouseListener) = throw IntentionPreviewUnsupportedOperationException() + override fun addEditorMouseMotionListener(listener: EditorMouseMotionListener) = throw IntentionPreviewUnsupportedOperationException() + override fun removeEditorMouseMotionListener(listener: EditorMouseMotionListener) = throw IntentionPreviewUnsupportedOperationException() + override fun isDisposed(): Boolean = throw IntentionPreviewUnsupportedOperationException() + override fun getProject(): Project? = throw IntentionPreviewUnsupportedOperationException() + override fun isInsertMode(): Boolean = throw IntentionPreviewUnsupportedOperationException() + override fun getSelectionModel(): SelectionModel = throw IntentionPreviewUnsupportedOperationException() + override fun isColumnMode(): Boolean = throw IntentionPreviewUnsupportedOperationException() + override fun isOneLineMode(): Boolean = throw IntentionPreviewUnsupportedOperationException() + override fun getGutter(): EditorGutter = throw IntentionPreviewUnsupportedOperationException() + override fun getMouseEventArea(e: MouseEvent): EditorMouseEventArea? = throw IntentionPreviewUnsupportedOperationException() + override fun setHeaderComponent(header: JComponent?) = throw IntentionPreviewUnsupportedOperationException() + override fun hasHeaderComponent(): Boolean = throw IntentionPreviewUnsupportedOperationException() + override fun getHeaderComponent(): JComponent? = throw IntentionPreviewUnsupportedOperationException() + override fun getIndentsModel(): IndentsModel = throw IntentionPreviewUnsupportedOperationException() + override fun getInlayModel(): InlayModel = throw IntentionPreviewUnsupportedOperationException() + override fun getEditorKind(): EditorKind = throw IntentionPreviewUnsupportedOperationException() inner class IntentionPreviewCaretModel : CaretModel { override fun moveToOffset(offset: Int) { caretOffset = offset } override fun getOffset(): Int = caretOffset - override fun moveCaretRelatively(columnShift: Int, lineShift: Int, withSelection: Boolean, blockSelection: Boolean, scrollToCaret: Boolean) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun moveToLogicalPosition(pos: LogicalPosition) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun moveToVisualPosition(pos: VisualPosition) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun moveToOffset(offset: Int, locateBeforeSoftWrap: Boolean) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun isUpToDate(): Boolean = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getLogicalPosition(): LogicalPosition = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getVisualPosition(): VisualPosition = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun addCaretListener(listener: CaretListener) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun removeCaretListener(listener: CaretListener) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getVisualLineStart(): Int = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getVisualLineEnd(): Int = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getTextAttributes(): TextAttributes = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun supportsMultipleCarets(): Boolean = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getCurrentCaret(): Caret = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getPrimaryCaret(): Caret = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getCaretCount(): Int = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getAllCarets(): MutableList = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getCaretAt(pos: VisualPosition): Caret? = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun addCaret(pos: VisualPosition): Caret? = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun addCaret(pos: VisualPosition, makePrimary: Boolean): Caret? = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun removeCaret(caret: Caret): Boolean = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun removeSecondaryCarets() = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun setCaretsAndSelections(caretStates: MutableList) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun setCaretsAndSelections(caretStates: MutableList, updateSystemSelection: Boolean) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun getCaretsAndSelections(): MutableList = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun runForEachCaret(action: CaretAction) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun runForEachCaret(action: CaretAction, reverseOrder: Boolean) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun addCaretActionListener(listener: CaretActionListener, disposable: Disposable) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) - override fun runBatchCaretOperation(runnable: Runnable) = throw UnsupportedOperationException(UNSUPPORTED_MESSAGE) + override fun moveCaretRelatively(columnShift: Int, lineShift: Int, withSelection: Boolean, blockSelection: Boolean, scrollToCaret: Boolean) = throw IntentionPreviewUnsupportedOperationException() + override fun moveToLogicalPosition(pos: LogicalPosition) = throw IntentionPreviewUnsupportedOperationException() + override fun moveToVisualPosition(pos: VisualPosition) = throw IntentionPreviewUnsupportedOperationException() + override fun moveToOffset(offset: Int, locateBeforeSoftWrap: Boolean) = throw IntentionPreviewUnsupportedOperationException() + override fun isUpToDate(): Boolean = throw IntentionPreviewUnsupportedOperationException() + override fun getLogicalPosition(): LogicalPosition = throw IntentionPreviewUnsupportedOperationException() + override fun getVisualPosition(): VisualPosition = throw IntentionPreviewUnsupportedOperationException() + override fun addCaretListener(listener: CaretListener) = throw IntentionPreviewUnsupportedOperationException() + override fun removeCaretListener(listener: CaretListener) = throw IntentionPreviewUnsupportedOperationException() + override fun getVisualLineStart(): Int = throw IntentionPreviewUnsupportedOperationException() + override fun getVisualLineEnd(): Int = throw IntentionPreviewUnsupportedOperationException() + override fun getTextAttributes(): TextAttributes = throw IntentionPreviewUnsupportedOperationException() + override fun supportsMultipleCarets(): Boolean = throw IntentionPreviewUnsupportedOperationException() + override fun getCurrentCaret(): Caret = throw IntentionPreviewUnsupportedOperationException() + override fun getPrimaryCaret(): Caret = throw IntentionPreviewUnsupportedOperationException() + override fun getCaretCount(): Int = throw IntentionPreviewUnsupportedOperationException() + override fun getAllCarets(): MutableList = throw IntentionPreviewUnsupportedOperationException() + override fun getCaretAt(pos: VisualPosition): Caret? = throw IntentionPreviewUnsupportedOperationException() + override fun addCaret(pos: VisualPosition): Caret? = throw IntentionPreviewUnsupportedOperationException() + override fun addCaret(pos: VisualPosition, makePrimary: Boolean): Caret? = throw IntentionPreviewUnsupportedOperationException() + override fun removeCaret(caret: Caret): Boolean = throw IntentionPreviewUnsupportedOperationException() + override fun removeSecondaryCarets() = throw IntentionPreviewUnsupportedOperationException() + override fun setCaretsAndSelections(caretStates: MutableList) = throw IntentionPreviewUnsupportedOperationException() + override fun setCaretsAndSelections(caretStates: MutableList, updateSystemSelection: Boolean) = throw IntentionPreviewUnsupportedOperationException() + override fun getCaretsAndSelections(): MutableList = throw IntentionPreviewUnsupportedOperationException() + override fun runForEachCaret(action: CaretAction) = throw IntentionPreviewUnsupportedOperationException() + override fun runForEachCaret(action: CaretAction, reverseOrder: Boolean) = throw IntentionPreviewUnsupportedOperationException() + override fun addCaretActionListener(listener: CaretActionListener, disposable: Disposable) = throw IntentionPreviewUnsupportedOperationException() + override fun runBatchCaretOperation(runnable: Runnable) = throw IntentionPreviewUnsupportedOperationException() } -} \ No newline at end of file +} + +class IntentionPreviewUnsupportedOperationException + : UnsupportedOperationException("It's unexpected to invoke this method on an intention preview calculating.") \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewEditorsPanel.kt b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewEditorsPanel.kt index 7fe8c69a75e8..38d58e5c38d1 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewEditorsPanel.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewEditorsPanel.kt @@ -10,7 +10,7 @@ import com.intellij.ui.JBColor import com.intellij.util.ui.JBUI import javax.swing.JPanel -class IntentionPreviewEditorsPanel(val editors: List) : JPanel(VerticalFlowLayout(0, 0)) { +internal class IntentionPreviewEditorsPanel(val editors: List) : JPanel(VerticalFlowLayout(0, 0)) { init { editors.forEachIndexed { index, editor -> add(editor.component) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewLoadingDecorator.kt b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewLoadingDecorator.kt index 0dfea443a6cf..b23f0de37bd7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewLoadingDecorator.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewLoadingDecorator.kt @@ -13,7 +13,7 @@ import java.awt.FlowLayout import javax.swing.JLabel import javax.swing.JPanel -class IntentionPreviewLoadingDecorator(panel: JPanel, project: Project) : +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 iconNonOpaquePanel = OpaquePanel(FlowLayout(FlowLayout.RIGHT, 2, 2)) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewModel.kt b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewModel.kt index 763ce75bef53..ffb701f831aa 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewModel.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewModel.kt @@ -17,7 +17,7 @@ import com.intellij.psi.PsiFile import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.util.ui.JBUI -class IntentionPreviewModel { +internal class IntentionPreviewModel { companion object { fun reformatRange(project: Project, psiFileCopy: PsiFile, lineFragment: LineFragment) { val start = lineFragment.startOffset2 @@ -66,16 +66,16 @@ class IntentionPreviewModel { val editor = (editorFactory.createEditor(document, project, fileType, false) as EditorEx) .also { it.setBorder(JBUI.Borders.empty(2, 0, 2, 0)) } - editor.settings.also { - it.isLineNumbersShown = true - it.isCaretRowShown = false - it.isLineMarkerAreaShown = false - it.isFoldingOutlineShown = false - it.additionalColumnsCount = 0 - it.additionalLinesCount = 0 - it.isRightMarginShown = false - it.isUseSoftWraps = false - it.isAdditionalPageAtBottom = false + editor.settings.apply { + isLineNumbersShown = true + isCaretRowShown = false + isLineMarkerAreaShown = false + isFoldingOutlineShown = false + additionalColumnsCount = 0 + additionalLinesCount = 0 + isRightMarginShown = false + isUseSoftWraps = false + isAdditionalPageAtBottom = false } editor.gutterComponentEx.also { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewPopupUpdateProcessor.kt b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewPopupUpdateProcessor.kt index 1b12d85c35c8..c2da231911bf 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewPopupUpdateProcessor.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/preview/IntentionPreviewPopupUpdateProcessor.kt @@ -7,14 +7,12 @@ 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.application.ApplicationManager +import com.intellij.openapi.actionSystem.CommonShortcuts.ESCAPE +import com.intellij.openapi.application.ReadAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.EditorFactory import com.intellij.openapi.editor.ex.EditorEx -import com.intellij.openapi.progress.EmptyProgressIndicator -import com.intellij.openapi.progress.ProcessCanceledException -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.progress.ProgressManager +import com.intellij.openapi.keymap.KeymapUtil import com.intellij.openapi.project.Project import com.intellij.openapi.ui.popup.JBPopup import com.intellij.openapi.ui.popup.JBPopupFactory @@ -22,17 +20,15 @@ import com.intellij.psi.PsiFile import com.intellij.ui.popup.PopupPositionManager import com.intellij.ui.popup.PopupUpdateProcessor import com.intellij.util.Alarm -import java.util.concurrent.Callable -import java.util.concurrent.Future +import com.intellij.util.concurrency.AppExecutorUtil +import org.jetbrains.concurrency.CancellablePromise import java.util.concurrent.TimeUnit -class IntentionPreviewPopupUpdateProcessor(private val project: Project, - private val originalFile: PsiFile, - private val originalEditor: Editor) : PopupUpdateProcessor(project) { +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 var progressIndicator: ProgressIndicator = EmptyProgressIndicator() private val alarm = Alarm() private lateinit var popup: JBPopup @@ -41,12 +37,10 @@ class IntentionPreviewPopupUpdateProcessor(private val project: Project, private var editorsToRelease = mutableListOf() - override fun updatePopup(lookupItemObject: Any?) { + override fun updatePopup(intentionAction: Any?) { if (!show) return alarm.cancelAllRequests() - progressIndicator.cancel() - if (!::popup.isInitialized || popup.isDisposed) { component = IntentionPreviewComponent(project) component.multiPanel.select(LOADING_PREVIEW, true) @@ -57,7 +51,7 @@ class IntentionPreviewPopupUpdateProcessor(private val project: Project, PopupPositionManager.positionPopupInBestPosition(popup, originalEditor, null) - updateAdvText.invoke(CodeInsightBundle.message("intention.preview.adv.hide.text")) + updateAdvText.invoke(CodeInsightBundle.message("intention.preview.adv.hide.text", Companion.ESCAPE_SHORTCUT_TEXT)) } val value = component.multiPanel.getValue(index, false) @@ -66,7 +60,7 @@ class IntentionPreviewPopupUpdateProcessor(private val project: Project, return } - val action = lookupItemObject as IntentionAction + val action = intentionAction as IntentionAction if (!action.startInWriteAction() || action.getElementToMakeWritable(originalFile) !== originalFile) { select(NO_PREVIEW) return @@ -86,7 +80,8 @@ class IntentionPreviewPopupUpdateProcessor(private val project: Project, component.removeAll() alarm.cancelAllRequests() show = false - updateAdvText.invoke(CodeInsightBundle.message("intention.preview.adv.show.text", IntentionHintComponent.ALT_SPACE_SHORTCUT_TEXT)) + updateAdvText.invoke( + CodeInsightBundle.message("intention.preview.adv.show.text", IntentionHintComponent.INTENTION_PREVIEW_SHORTCUT_TEXT)) return true } @@ -94,21 +89,13 @@ class IntentionPreviewPopupUpdateProcessor(private val project: Project, private val action: IntentionAction, private val originalFile: PsiFile, private val originalEditor: Editor) : Runnable { - lateinit var computation: Future>?> + lateinit var computation: CancellablePromise>?> fun start() { component.startLoading() - computation = ApplicationManager.getApplication().executeOnPooledThread( - Callable { - try { - ProgressManager.getInstance().runProcess(IntentionPreviewComputable(project, action, originalFile, originalEditor), - progressIndicator) - } - catch (e: ProcessCanceledException) { - Pair>(null, emptyList()) - } - }) + computation = ReadAction.nonBlocking>>( + IntentionPreviewComputable(project, action, originalFile, originalEditor)).submit(AppExecutorUtil.getAppExecutorService()) alarm.addRequest(this, 100) } @@ -146,4 +133,8 @@ class IntentionPreviewPopupUpdateProcessor(private val project: Project, popup.pack(true, true) } + + companion object { + private val ESCAPE_SHORTCUT_TEXT = KeymapUtil.getPreferredShortcutText(ESCAPE.shortcuts) + } } \ No newline at end of file diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index 2d9769ba62f7..92059fae8689 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -269,7 +269,7 @@ intention.wrap.with.unmodifiable.set=Wrap with unmodifiable set intention.wrap.with.unmodifiable.map=Wrap with unmodifiable map intention.preview.adv.show.text=Press {0} to open preview -intention.preview.adv.hide.text=Press Escape to hide preview +intention.preview.adv.hide.text=Press {0} to hide preview intention.preview.no.available.text=Preview isn't available intention.preview.loading.preview=Loading... intention.preview.initial.loading.preview=Intention Preview