diff --git a/CHANGELOG.md b/CHANGELOG.md index 514040150..bf89235cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - Added shortcut `shift + alt + enter` for execute ImpEx action [#839](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/839) - Added shortcut `control + alt + V` for Validate ImpEx action [#844](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/844) - Added shortcut `control + shift + alt + O` for Open ImpEx action [#845](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/845) +- Omit slow operation on Column Highlighting under the caret [#847](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/847) ### Other - Adjust optional dependency on `AntPlugin` during project refresh [#833](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/833) diff --git a/resources/META-INF/lang/impex-dependencies.xml b/resources/META-INF/lang/impex-dependencies.xml index 3d46a3eca..620f0fad9 100644 --- a/resources/META-INF/lang/impex-dependencies.xml +++ b/resources/META-INF/lang/impex-dependencies.xml @@ -83,10 +83,6 @@ - - - - - - diff --git a/src/com/intellij/idea/plugin/hybris/impex/actions/AbstractImpExTableColumnMoveAction.kt b/src/com/intellij/idea/plugin/hybris/impex/actions/AbstractImpExTableColumnMoveAction.kt index 2c11849ad..d429a0115 100644 --- a/src/com/intellij/idea/plugin/hybris/impex/actions/AbstractImpExTableColumnMoveAction.kt +++ b/src/com/intellij/idea/plugin/hybris/impex/actions/AbstractImpExTableColumnMoveAction.kt @@ -17,8 +17,7 @@ */ package com.intellij.idea.plugin.hybris.impex.actions -import com.intellij.idea.plugin.hybris.impex.assistance.ImpexColumnHighlighterService -import com.intellij.idea.plugin.hybris.impex.assistance.ImpexHeaderNameHighlighterService +import com.intellij.idea.plugin.hybris.impex.assistance.event.ImpexHighlightingCaretListener import com.intellij.idea.plugin.hybris.impex.psi.ImpexFullHeaderParameter import com.intellij.idea.plugin.hybris.impex.psi.ImpexHeaderLine import com.intellij.idea.plugin.hybris.impex.psi.ImpexValueGroup @@ -39,6 +38,8 @@ abstract class AbstractImpExTableColumnMoveAction(private val direction: ImpExCo } private fun move(editor: Editor, headerParameter: ImpexFullHeaderParameter, elementAtCaret: PsiElement, direction: ImpExColumnPosition) { + ImpexHighlightingCaretListener.instance.clearHighlightedArea(editor) + val headerLine = headerParameter.headerLine ?: return val column = headerParameter.columnNumber @@ -53,9 +54,6 @@ abstract class AbstractImpExTableColumnMoveAction(private val direction: ImpExCo newElementAtCaret ?.let { - ImpexColumnHighlighterService.instance.releaseEditorData(editor) - ImpexHeaderNameHighlighterService.instance.releaseEditorData(editor) - val caretOffsetInText = previousOffset - previousElementStartOffset editor.caretModel.currentCaret.moveToOffset(it.startOffset + caretOffsetInText) } diff --git a/src/com/intellij/idea/plugin/hybris/impex/assistance/AbstractImpexHighlighterService.java b/src/com/intellij/idea/plugin/hybris/impex/assistance/AbstractImpexHighlighterService.java deleted file mode 100644 index 7d778787f..000000000 --- a/src/com/intellij/idea/plugin/hybris/impex/assistance/AbstractImpexHighlighterService.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of "hybris integration" plugin for Intellij IDEA. - * Copyright (C) 2014-2016 Alexander Bartash - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.intellij.idea.plugin.hybris.impex.assistance; - -import com.intellij.codeInsight.highlighting.HighlightManager; -import com.intellij.codeInsight.highlighting.HighlightManagerImpl; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.markup.RangeHighlighter; -import com.intellij.openapi.util.TextRange; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; -import java.util.Objects; - -public abstract class AbstractImpexHighlighterService implements ImpexHighlighterService { - - /** - * IIPS-174: It seems like sometimes when we highlight code inside "Code Preview Panel" in combination with OOTB - * "unchanged lines" folding from IDEA it can end up in creating invalid highlighting ranges. - * E.g. when you run an inspection for an impex file and in the results panel click on an inspection result - * on the right it shows you a preview of a snippet from that file, and if you have multiple inspection warnings in - * the same file when you click on them the preview panel jumps into different parts of the file, which leads to - * creation of multiple highlight ranges while the editor stays the same, but OOTB folding messes everything up by - * folding many lines as the result highlight ranges created for the first inspection have invalid start and end - * offsets for the editor with folded lines when you click on some other inspection from the same file. - */ - protected void removeInvalidRangeHighlighters(@NotNull final Editor editor) { - final HighlightManager highlightManager = HighlightManager.getInstance( - Objects.requireNonNull(editor.getProject()) - ); - - final RangeHighlighter[] highlighters = ((HighlightManagerImpl) highlightManager).getHighlighters(editor); - - Arrays.stream(highlighters) - .filter(this::isNotProperRangeHighlighter) - .forEach(highlighter -> highlightManager.removeSegmentHighlighter(editor, highlighter)); - } - - /** - * From {@link TextRange#isProperRange(int, int) TextRange#isProperRange(int, int)) - */ - protected boolean isNotProperRangeHighlighter(@NotNull RangeHighlighter rangeHighlighter) { - return rangeHighlighter.getStartOffset() > rangeHighlighter.getEndOffset() || rangeHighlighter.getStartOffset() < 0; - } -} diff --git a/src/com/intellij/idea/plugin/hybris/impex/assistance/DefaultImpexColumnHighlighterService.java b/src/com/intellij/idea/plugin/hybris/impex/assistance/DefaultImpexColumnHighlighterService.java deleted file mode 100644 index 7d40983b4..000000000 --- a/src/com/intellij/idea/plugin/hybris/impex/assistance/DefaultImpexColumnHighlighterService.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA. - * Copyright (C) 2014-2016 Alexander Bartash - * Copyright (C) 2019-2023 EPAM Systems and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.intellij.idea.plugin.hybris.impex.assistance; - -import com.intellij.codeInsight.folding.impl.FoldingUtil; -import com.intellij.codeInsight.highlighting.HighlightManager; -import com.intellij.codeInsight.highlighting.HighlightUsagesHandler; -import com.intellij.idea.plugin.hybris.impex.psi.ImpexValue; -import com.intellij.idea.plugin.hybris.impex.psi.ImpexValueGroup; -import com.intellij.idea.plugin.hybris.impex.utils.ImpexPsiUtils; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.colors.EditorColors; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiElement; -import com.intellij.psi.SmartPointerManager; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - - -public class DefaultImpexColumnHighlighterService - extends AbstractImpexHighlighterService - implements ImpexColumnHighlighterService { - - private final static Key> CACHE_KEY = Key.create("IMPEX_COLUMN_HIGHLIGHT_CACHE"); - - @Override - @Contract - public void highlight(@NotNull final Editor editor) { - ApplicationManager.getApplication().invokeLater(() -> highlightColumnOfValueUnderCaret(editor)); - } - - @Contract - protected void highlightColumnOfValueUnderCaret(@NotNull final Editor editor) { - final var headerParameter = ImpexPsiUtils.getFullHeaderParameterUnderCaret(editor); - if (headerParameter == null) { - clearHighlightedArea(editor); - return; - } - - final var values = headerParameter.getValueGroups().stream() - .map(ImpexValueGroup::getValue) - .filter(Objects::nonNull) - .toList(); - - if (values.isEmpty()) { - clearHighlightedArea(editor); - } else if (editor.getProject() != null) { - final var pointerManager = SmartPointerManager.getInstance(editor.getProject()); - highlightArea(editor, values); - } - } - - @Contract - protected void highlightArea( - @NotNull final Editor editor, - final List values - ) { - if (isAlreadyHighlighted(editor, values)) { - return; - } - - final var currentHighlightedElement = editor.getUserData(CACHE_KEY); - editor.putUserData(CACHE_KEY, null); - if (null != currentHighlightedElement) { - modifyHighlightedArea(editor, currentHighlightedElement, true); - } - - editor.putUserData(CACHE_KEY, values); - modifyHighlightedArea(editor, values, false); - } - - @Contract - protected void clearHighlightedArea(@NotNull final Editor editor) { - final var column = editor.getUserData(CACHE_KEY); - if (column != null) { - editor.putUserData(CACHE_KEY, null); - modifyHighlightedArea(editor, column, true); - } - } - - @Contract - protected boolean isAlreadyHighlighted( - @NotNull final Editor editor, - final List ranges - ) { - return Objects.equals(editor.getUserData(CACHE_KEY), ranges); - } - - @Contract - protected void modifyHighlightedArea( - @NotNull final Editor editor, - final List column, - final boolean clear - ) { - Validate.notNull(column); - - if (null == editor.getProject()) { - return; - } - - if (editor.getProject().isDisposed()) { - return; - } - - this.removeInvalidRangeHighlighters(editor); - - // This list must be modifiable - // https://hybris-integration.atlassian.net/browse/IIP-11 - final List ranges = column - .stream() - .map(PsiElement::getTextRange) - .filter(textRange -> !FoldingUtil.isTextRangeFolded(editor, textRange)) - // Do not use Collectors.toList() here because: - // There are no guarantees on the type, mutability, serializability, - // or thread-safety of the List returned; if more control over the - // returned List is required, use toCollection(Supplier). - .collect(Collectors.toCollection(ArrayList::new)); - - if (CollectionUtils.isNotEmpty(ranges)) { - HighlightUsagesHandler.highlightRanges( - HighlightManager.getInstance(editor.getProject()), - editor, - EditorColors.SEARCH_RESULT_ATTRIBUTES, - clear, - ranges - ); - } - } - - @Override - @Contract - public void releaseEditorData(@NotNull final Editor editor) { - editor.putUserData(CACHE_KEY, null); - } - -} \ No newline at end of file diff --git a/src/com/intellij/idea/plugin/hybris/impex/assistance/DefaultImpexHeaderNameHighlighterService.kt b/src/com/intellij/idea/plugin/hybris/impex/assistance/DefaultImpexHeaderNameHighlighterService.kt deleted file mode 100644 index 29f531367..000000000 --- a/src/com/intellij/idea/plugin/hybris/impex/assistance/DefaultImpexHeaderNameHighlighterService.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA. - * Copyright (C) 2019-2023 EPAM Systems and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.intellij.idea.plugin.hybris.impex.assistance - -import com.intellij.codeInsight.folding.impl.FoldingUtil -import com.intellij.codeInsight.highlighting.HighlightManager -import com.intellij.codeInsight.highlighting.HighlightUsagesHandler -import com.intellij.idea.plugin.hybris.impex.utils.ImpexPsiUtils -import com.intellij.openapi.application.invokeLater -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.editor.colors.EditorColors -import com.intellij.openapi.util.TextRange -import com.intellij.psi.PsiElement - -class DefaultImpexHeaderNameHighlighterService : AbstractImpexHighlighterService(), ImpexHeaderNameHighlighterService { - - private val highlightedBlocks = mutableMapOf() - - override fun highlight(editor: Editor) { - invokeLater { - ImpexPsiUtils.getHeaderOfValueGroupUnderCaret(editor) - ?.let { highlightArea(editor, it) } - ?: clearHighlightedArea(editor) - } - } - - private fun highlightArea( - editor: Editor, - impexFullHeaderParameter: PsiElement - ) { - if (isAlreadyHighlighted(editor, impexFullHeaderParameter)) return - - highlightedBlocks.remove(editor) - ?.let { modifyHighlightedArea(editor, it, true) } - - highlightedBlocks[editor] = impexFullHeaderParameter - modifyHighlightedArea(editor, impexFullHeaderParameter) - } - - private fun clearHighlightedArea(editor: Editor) { - if (highlightedBlocks.isEmpty()) return - - val impexFullHeaderParameter = highlightedBlocks.remove(editor) ?: return - - modifyHighlightedArea(editor, impexFullHeaderParameter, true) - } - - private fun isAlreadyHighlighted(editor: Editor, fullHeaderParameter: PsiElement) = - highlightedBlocks[editor] == fullHeaderParameter - - private fun modifyHighlightedArea( - editor: Editor, - impexFullHeaderParameter: PsiElement, - clear: Boolean = false, - ) { - val project = editor.project ?: return - if (project.isDisposed) return - - removeInvalidRangeHighlighters(editor) - - if (FoldingUtil.isTextRangeFolded(editor, impexFullHeaderParameter.textRange)) return - - val ranges = mutableListOf() - ranges.add(impexFullHeaderParameter.textRange) - - HighlightUsagesHandler.highlightRanges( - HighlightManager.getInstance(project), - editor, - EditorColors.SEARCH_RESULT_ATTRIBUTES, - clear, - ranges - ) - } - - override fun releaseEditorData(editor: Editor) { - highlightedBlocks.remove(editor) - } -} diff --git a/src/com/intellij/idea/plugin/hybris/impex/assistance/ImpexColumnHighlighterService.kt b/src/com/intellij/idea/plugin/hybris/impex/assistance/ImpexColumnHighlighterService.kt deleted file mode 100644 index 5bf33b19d..000000000 --- a/src/com/intellij/idea/plugin/hybris/impex/assistance/ImpexColumnHighlighterService.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is part of "hybris integration" plugin for Intellij IDEA. - * Copyright (C) 2019 EPAM Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.intellij.idea.plugin.hybris.impex.assistance; - -import com.intellij.openapi.application.ApplicationManager; - -interface ImpexColumnHighlighterService : ImpexHighlighterService { - - companion object { - val instance: ImpexColumnHighlighterService = ApplicationManager.getApplication().getService(ImpexColumnHighlighterService::class.java) - } -} diff --git a/src/com/intellij/idea/plugin/hybris/impex/assistance/ImpexHeaderNameHighlighterService.kt b/src/com/intellij/idea/plugin/hybris/impex/assistance/ImpexHeaderNameHighlighterService.kt deleted file mode 100644 index 7a5659159..000000000 --- a/src/com/intellij/idea/plugin/hybris/impex/assistance/ImpexHeaderNameHighlighterService.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is part of "hybris integration" plugin for Intellij IDEA. - * Copyright (C) 2019 EPAM Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.intellij.idea.plugin.hybris.impex.assistance; - -import com.intellij.openapi.application.ApplicationManager; - -interface ImpexHeaderNameHighlighterService : ImpexHighlighterService { - - companion object { - val instance: ImpexHeaderNameHighlighterService = ApplicationManager.getApplication().getService(ImpexHeaderNameHighlighterService::class.java) - } -} \ No newline at end of file diff --git a/src/com/intellij/idea/plugin/hybris/impex/assistance/ImpexHighlighterService.kt b/src/com/intellij/idea/plugin/hybris/impex/assistance/ImpexHighlighterService.kt deleted file mode 100644 index b9d1d74c7..000000000 --- a/src/com/intellij/idea/plugin/hybris/impex/assistance/ImpexHighlighterService.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is part of "hybris integration" plugin for Intellij IDEA. - * Copyright (C) 2019 EPAM Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.intellij.idea.plugin.hybris.impex.assistance; - -import com.intellij.openapi.editor.Editor; - -interface ImpexHighlighterService { - - fun highlight(editor: Editor) - - fun releaseEditorData(editor: Editor) -} diff --git a/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexColumnHighlightingCaretListener.kt b/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexColumnHighlightingCaretListener.kt deleted file mode 100644 index 2864b8668..000000000 --- a/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexColumnHighlightingCaretListener.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA. - * Copyright (C) 2019-2023 EPAM Systems and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -package com.intellij.idea.plugin.hybris.impex.assistance.event - -import com.intellij.idea.plugin.hybris.common.services.CommonIdeaService -import com.intellij.idea.plugin.hybris.impex.assistance.ImpexColumnHighlighterService -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.components.Service -import com.intellij.openapi.editor.event.CaretEvent -import com.intellij.openapi.editor.event.CaretListener - -@Service -class ImpexColumnHighlightingCaretListener : CaretListener { - - override fun caretPositionChanged(e: CaretEvent) { - if (CommonIdeaService.instance.isTypingActionInProgress()) return - - ImpexColumnHighlighterService.instance.highlight(e.editor) - } - - override fun caretAdded(e: CaretEvent) {} - override fun caretRemoved(e: CaretEvent) {} - - companion object { - val instance: ImpexColumnHighlightingCaretListener = ApplicationManager.getApplication().getService(ImpexColumnHighlightingCaretListener::class.java) - } - -} \ No newline at end of file diff --git a/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexEditorFactoryListener.kt b/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexEditorFactoryListener.kt index 55171baf6..55c9b8784 100644 --- a/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexEditorFactoryListener.kt +++ b/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexEditorFactoryListener.kt @@ -1,6 +1,6 @@ /* * This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA. - * Copyright (C) 2019 EPAM Systems + * Copyright (C) 2019-2023 EPAM Systems and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as @@ -17,20 +17,25 @@ */ package com.intellij.idea.plugin.hybris.impex.assistance.event -import com.intellij.idea.plugin.hybris.impex.assistance.ImpexColumnHighlighterService -import com.intellij.idea.plugin.hybris.impex.assistance.ImpexHeaderNameHighlighterService import com.intellij.openapi.editor.event.EditorFactoryEvent import com.intellij.openapi.editor.event.EditorFactoryListener class ImpexEditorFactoryListener : EditorFactoryListener { - private val impexColumnHighlighterService = ImpexColumnHighlighterService.instance - private val impexHeaderNameHighlighterService = ImpexHeaderNameHighlighterService.instance + override fun editorCreated(editorFactoryEvent: EditorFactoryEvent) { + val editor = editorFactoryEvent.editor - override fun editorCreated(editorFactoryEvent: EditorFactoryEvent) {} + with(ImpexHighlightingCaretListener.instance) { + editor.caretModel.addCaretListener(this) + } + } override fun editorReleased(editorFactoryEvent: EditorFactoryEvent) { - impexHeaderNameHighlighterService.releaseEditorData(editorFactoryEvent.editor) - impexColumnHighlighterService.releaseEditorData(editorFactoryEvent.editor) + val editor = editorFactoryEvent.editor + + with(ImpexHighlightingCaretListener.instance) { + this.clearHighlightedArea(editor) + editor.caretModel.removeCaretListener(this) + } } } \ No newline at end of file diff --git a/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexHeaderHighlightingCaretListener.kt b/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexHeaderHighlightingCaretListener.kt deleted file mode 100644 index 6593c294a..000000000 --- a/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexHeaderHighlightingCaretListener.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA. - * Copyright (C) 2019-2023 EPAM Systems and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -package com.intellij.idea.plugin.hybris.impex.assistance.event - -import com.intellij.idea.plugin.hybris.common.services.CommonIdeaService -import com.intellij.idea.plugin.hybris.impex.assistance.ImpexHeaderNameHighlighterService -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.components.Service -import com.intellij.openapi.editor.event.CaretEvent -import com.intellij.openapi.editor.event.CaretListener - -@Service -class ImpexHeaderHighlightingCaretListener : CaretListener { - - override fun caretPositionChanged(e: CaretEvent) { - if (CommonIdeaService.instance.isTypingActionInProgress()) return - - ImpexHeaderNameHighlighterService.instance.highlight(e.editor) - } - - override fun caretAdded(e: CaretEvent) {} - override fun caretRemoved(e: CaretEvent) {} - - companion object { - val instance: ImpexHeaderHighlightingCaretListener = ApplicationManager.getApplication().getService(ImpexHeaderHighlightingCaretListener::class.java) - } - -} \ No newline at end of file diff --git a/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexHighlightingCaretListener.kt b/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexHighlightingCaretListener.kt new file mode 100644 index 000000000..28b81d68c --- /dev/null +++ b/src/com/intellij/idea/plugin/hybris/impex/assistance/event/ImpexHighlightingCaretListener.kt @@ -0,0 +1,161 @@ +/* + * This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA. + * Copyright (C) 2019-2023 EPAM Systems and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package com.intellij.idea.plugin.hybris.impex.assistance.event + +import com.intellij.codeInsight.folding.impl.FoldingUtil +import com.intellij.codeInsight.highlighting.HighlightManager +import com.intellij.codeInsight.highlighting.HighlightManagerImpl +import com.intellij.codeInsight.highlighting.HighlightUsagesHandler +import com.intellij.idea.plugin.hybris.common.services.CommonIdeaService +import com.intellij.idea.plugin.hybris.impex.ImpexLanguage +import com.intellij.idea.plugin.hybris.impex.psi.ImpexFullHeaderParameter +import com.intellij.idea.plugin.hybris.impex.utils.ImpexPsiUtils +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.ModalityState +import com.intellij.openapi.application.ReadAction +import com.intellij.openapi.components.Service +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.colors.EditorColors +import com.intellij.openapi.editor.event.CaretEvent +import com.intellij.openapi.editor.event.CaretListener +import com.intellij.openapi.editor.markup.RangeHighlighter +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.TextRange +import com.intellij.openapi.util.removeUserData +import com.intellij.psi.PsiElement +import com.intellij.psi.util.PsiUtilBase +import com.intellij.util.concurrency.AppExecutorUtil + +@Service +class ImpexHighlightingCaretListener : CaretListener { + + override fun caretAdded(e: CaretEvent) {} + override fun caretRemoved(e: CaretEvent) {} + + override fun caretPositionChanged(e: CaretEvent) { + if (CommonIdeaService.instance.isTypingActionInProgress()) return + + val editor = e.editor + val project = editor.project ?: return + if (project.isDisposed) return + + ReadAction + .nonBlocking> { + if (PsiUtilBase.getLanguageInEditor(editor, project) !is ImpexLanguage) return@nonBlocking emptyList() + + ImpexPsiUtils.getHeaderOfValueGroupUnderCaret(editor) + ?.let { it as? ImpexFullHeaderParameter } + ?.let { listOf(it) } + ?: ImpexPsiUtils.getFullHeaderParameterUnderCaret(editor) + ?.valueGroups + ?.let { it.mapNotNull { ivg -> ivg.value } } + ?: emptyList() + } + .withDocumentsCommitted(project) + .expireWhen { editor.isDisposed } + .finishOnUiThread(ModalityState.defaultModalityState()) { + it.takeIf { it.isNotEmpty() } + ?.map { psiElement -> psiElement.textRange } + ?.filterNot { textRange -> FoldingUtil.isTextRangeFolded(editor, textRange) } + ?.let { textRanges -> highlightArea(editor, textRanges, project) } + ?: clearHighlightedArea(editor) + } + .submit(AppExecutorUtil.getAppExecutorService()) + } + + fun clearHighlightedArea(editor: Editor) { + editor.removeUserData(CACHE_KEY) + ?.let { + editor.project + ?.let { project -> modifyHighlightedArea(editor, it, project, true) } + } + } + + private fun highlightArea(editor: Editor, values: List, project: Project) { + if (isAlreadyHighlighted(editor, values)) return + + clearHighlightedArea(editor) + + modifyHighlightedArea(editor, values, project, false) + + editor.putUserData(CACHE_KEY, values) + } + + private fun modifyHighlightedArea( + editor: Editor, + textRanges: List, + project: Project, + clear: Boolean + ) { + val highlightManager = HighlightManager.getInstance(project) + removeInvalidRangeHighlighters(editor, highlightManager) + + // This list must be modifiable + // https://hybris-integration.atlassian.net/browse/IIP-11 + textRanges + // Do not use Collectors.toList() here because: + // There are no guarantees on the type, mutability, serializability, + // or thread-safety of the List returned; if more control over the + // returned List is required, use toCollection(Supplier). + .toMutableList() + .takeIf { it.isNotEmpty() } + ?.let { + HighlightUsagesHandler.highlightRanges( + highlightManager, + editor, + EditorColors.SEARCH_RESULT_ATTRIBUTES, + clear, + it + ) + } + } + + /** + * IIPS-174: It seems like sometimes when we highlight code inside "Code Preview Panel" in combination with OOTB + * "unchanged lines" folding from IDEA it can end up in creating invalid highlighting ranges. + * E.g. when you run an inspection for an impex file and in the results panel click on an inspection result + * on the right it shows you a preview of a snippet from that file, and if you have multiple inspection warnings in + * the same file when you click on them the preview panel jumps into different parts of the file, which leads to + * creation of multiple highlight ranges while the editor stays the same, but OOTB folding messes everything up by + * folding many lines as the result highlight ranges created for the first inspection have invalid start and end + * offsets for the editor with folded lines when you click on some other inspection from the same file. + */ + private fun removeInvalidRangeHighlighters(editor: Editor, highlightManager: HighlightManager) { + if (highlightManager !is HighlightManagerImpl) return + + highlightManager.getHighlighters(editor) + .filter { isNotProperRangeHighlighter(it) } + .forEach { highlightManager.removeSegmentHighlighter(editor, it) } + } + + /** + * From [TextRange#isProperRange(int, int))][TextRange.isProperRange] + */ + private fun isNotProperRangeHighlighter(rangeHighlighter: RangeHighlighter) = rangeHighlighter.startOffset > rangeHighlighter.endOffset + || rangeHighlighter.startOffset < 0 + + private fun isAlreadyHighlighted(editor: Editor, ranges: List) = editor.getUserData(CACHE_KEY) == ranges + + companion object { + private val CACHE_KEY = Key.create>("IMPEX_COLUMN_HIGHLIGHT_CACHE") + + val instance: ImpexHighlightingCaretListener = ApplicationManager.getApplication().getService(ImpexHighlightingCaretListener::class.java) + } + +} \ No newline at end of file diff --git a/src/com/intellij/idea/plugin/hybris/impex/psi/ImpexPsiManager.kt b/src/com/intellij/idea/plugin/hybris/impex/psi/ImpexPsiManager.kt deleted file mode 100644 index 426901e2e..000000000 --- a/src/com/intellij/idea/plugin/hybris/impex/psi/ImpexPsiManager.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA. - * Copyright (C) 2019-2023 EPAM Systems and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -package com.intellij.idea.plugin.hybris.impex.psi - -import com.intellij.idea.plugin.hybris.impex.assistance.event.ImpexColumnHighlightingCaretListener -import com.intellij.idea.plugin.hybris.impex.assistance.event.ImpexHeaderHighlightingCaretListener -import com.intellij.openapi.Disposable -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.components.Service -import com.intellij.openapi.editor.EditorFactory - -@Service -class ImpexPsiManager : Disposable { - - fun registerListeners() { - with(EditorFactory.getInstance()) { - this.eventMulticaster.addCaretListener(ImpexHeaderHighlightingCaretListener.instance, this@ImpexPsiManager) - this.eventMulticaster.addCaretListener(ImpexColumnHighlightingCaretListener.instance, this@ImpexPsiManager) - } - } - - override fun dispose() = Unit - - companion object { - val instance: ImpexPsiManager = ApplicationManager.getApplication().getService(ImpexPsiManager::class.java) - } - -} diff --git a/src/com/intellij/idea/plugin/hybris/impex/psi/ImpexPsiTreeChangeListener.kt b/src/com/intellij/idea/plugin/hybris/impex/psi/ImpexPsiTreeChangeListener.kt deleted file mode 100644 index 4283e60d9..000000000 --- a/src/com/intellij/idea/plugin/hybris/impex/psi/ImpexPsiTreeChangeListener.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA. - * Copyright (C) 2023 EPAM Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -package com.intellij.idea.plugin.hybris.impex.psi - -import com.intellij.idea.plugin.hybris.impex.ImpexLanguage -import com.intellij.idea.plugin.hybris.impex.assistance.ImpexColumnHighlighterService -import com.intellij.idea.plugin.hybris.impex.assistance.ImpexHeaderNameHighlighterService -import com.intellij.psi.PsiTreeChangeEvent -import com.intellij.psi.PsiTreeChangeListener -import com.intellij.psi.util.PsiEditorUtil -import com.intellij.psi.util.PsiUtilBase - -class ImpexPsiTreeChangeListener : PsiTreeChangeListener { - - private fun highlightHeader(psiTreeChangeEvent: PsiTreeChangeEvent) { - val file = psiTreeChangeEvent.file ?: return - val editor = PsiEditorUtil.findEditor(file) ?: return - val project = editor.project ?: return - if (project.isDisposed) return - - if (PsiUtilBase.getLanguageInEditor(editor, project) is ImpexLanguage) { - ImpexHeaderNameHighlighterService.instance.highlight(editor) - ImpexColumnHighlighterService.instance.highlight(editor) - } - } - - override fun childAdded(psiTreeChangeEvent: PsiTreeChangeEvent) { - highlightHeader(psiTreeChangeEvent) - } - - override fun childRemoved(psiTreeChangeEvent: PsiTreeChangeEvent) { - highlightHeader(psiTreeChangeEvent) - } - - override fun childReplaced(psiTreeChangeEvent: PsiTreeChangeEvent) { - highlightHeader(psiTreeChangeEvent) - } - - override fun childMoved(psiTreeChangeEvent: PsiTreeChangeEvent) { - highlightHeader(psiTreeChangeEvent) - } - - - override fun beforeChildAddition(psiTreeChangeEvent: PsiTreeChangeEvent) = Unit - override fun beforeChildRemoval(psiTreeChangeEvent: PsiTreeChangeEvent) = Unit - override fun beforeChildReplacement(psiTreeChangeEvent: PsiTreeChangeEvent) = Unit - override fun beforeChildMovement(psiTreeChangeEvent: PsiTreeChangeEvent) = Unit - override fun beforeChildrenChange(psiTreeChangeEvent: PsiTreeChangeEvent) = Unit - override fun beforePropertyChange(psiTreeChangeEvent: PsiTreeChangeEvent) = Unit - override fun childrenChanged(psiTreeChangeEvent: PsiTreeChangeEvent) = Unit - override fun propertyChanged(psiTreeChangeEvent: PsiTreeChangeEvent) = Unit -} \ No newline at end of file diff --git a/src/com/intellij/idea/plugin/hybris/impex/utils/ImpexPsiUtils.java b/src/com/intellij/idea/plugin/hybris/impex/utils/ImpexPsiUtils.java index b2328f36b..443efbbc8 100644 --- a/src/com/intellij/idea/plugin/hybris/impex/utils/ImpexPsiUtils.java +++ b/src/com/intellij/idea/plugin/hybris/impex/utils/ImpexPsiUtils.java @@ -1,6 +1,7 @@ /* - * This file is part of "hybris integration" plugin for Intellij IDEA. + * This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA. * Copyright (C) 2014-2016 Alexander Bartash + * Copyright (C) 2019-2023 EPAM Systems and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as @@ -310,6 +311,7 @@ public static PsiElement getPrevValueLine(@NotNull final PsiElement element) { } + @Nullable public static PsiElement getHeaderOfValueGroupUnderCaret(@NotNull final Editor editor) { Validate.notNull(editor); @@ -323,7 +325,8 @@ public static PsiElement getHeaderOfValueGroupUnderCaret(@NotNull final Editor e return getHeaderForValueGroup(valueGroup); } - public static @Nullable ImpexFullHeaderParameter getFullHeaderParameterUnderCaret(@NotNull final Editor editor) { + @Nullable + public static ImpexFullHeaderParameter getFullHeaderParameterUnderCaret(@NotNull final Editor editor) { final var psiElementUnderCaret = PsiUtilBase.getElementAtCaret(editor); if (psiElementUnderCaret == null) return null; diff --git a/src/com/intellij/idea/plugin/hybris/project/providers/HybrisWritingAccessProvider.java b/src/com/intellij/idea/plugin/hybris/project/providers/HybrisWritingAccessProvider.java index b68fb3775..9c7e2950d 100644 --- a/src/com/intellij/idea/plugin/hybris/project/providers/HybrisWritingAccessProvider.java +++ b/src/com/intellij/idea/plugin/hybris/project/providers/HybrisWritingAccessProvider.java @@ -20,11 +20,9 @@ package com.intellij.idea.plugin.hybris.project.providers; import com.intellij.idea.plugin.hybris.settings.HybrisProjectSettingsComponent; -import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Key; -import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.WritingAccessProvider; import com.intellij.util.ObjectUtils; @@ -97,15 +95,7 @@ protected boolean isFileReadOnly(@NotNull final VirtualFile file) { return false; } - return Arrays.stream(ModuleManager.getInstance(myProject).getModules()) - .filter(module -> { - for (final var contentRoot : ModuleRootManager.getInstance(module).getContentRoots()) { - if (VfsUtilCore.isAncestor(contentRoot, file, false)) return true; - } - return false; - } - ) - .findFirst() + return Optional.ofNullable(ModuleUtil.findModuleForFile(file, myProject)) .map(module -> HybrisProjectSettingsComponent.getInstance(myProject) .getModuleSettings(module) .getReadonly() @@ -114,7 +104,7 @@ protected boolean isFileReadOnly(@NotNull final VirtualFile file) { } private boolean isTemporarilyWritable(@NotNull final VirtualFile vFile) { - Boolean excluded = vFile.getUserData(KEY_TEMPORARY_WRITABLE); + final Boolean excluded = vFile.getUserData(KEY_TEMPORARY_WRITABLE); return excluded != null && excluded; } diff --git a/src/com/intellij/idea/plugin/hybris/startup/ImpexHeaderHighlighterStartupActivity.kt b/src/com/intellij/idea/plugin/hybris/startup/ImpexHeaderHighlighterStartupActivity.kt deleted file mode 100644 index e3fff1210..000000000 --- a/src/com/intellij/idea/plugin/hybris/startup/ImpexHeaderHighlighterStartupActivity.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA. - * Copyright (C) 2023 EPAM Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -package com.intellij.idea.plugin.hybris.startup - -import com.intellij.idea.plugin.hybris.impex.psi.ImpexPsiManager -import com.intellij.idea.plugin.hybris.settings.HybrisProjectSettingsComponent -import com.intellij.openapi.project.Project -import com.intellij.openapi.startup.ProjectActivity - -class ImpexHeaderHighlighterStartupActivity : ProjectActivity { - - override suspend fun execute(project: Project) { - if (!HybrisProjectSettingsComponent.getInstance(project).isHybrisProject()) return - - ImpexPsiManager.instance.registerListeners(); - } -} \ No newline at end of file