diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/ex/InjectedAwareEditorRepaintStrategy.java b/platform/lang-impl/src/com/intellij/openapi/editor/ex/InjectedAwareEditorRepaintStrategy.java new file mode 100644 index 000000000000..7943c243e182 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/editor/ex/InjectedAwareEditorRepaintStrategy.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.ex; + +import com.intellij.injected.editor.DocumentWindow; +import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.editor.impl.EditorRepaintStrategy; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * This strategy handles the situation when typing is performed inside parsed injected text. Usually editor's highlighter + * doesn't know anything about injected context internals and sees it just as a single big token (e.g. MXML files may contain + * Flash code inside CDATA comment and the highlighter (based on XML lexer) considers the whole Flash code block to be just + * a CDATA token). + *

+ * So, every time user types at injected context, highlighter receives document change event and asks editor to repaint + * affected token. That is rather heavy operation if performed frequently for the large text range. That's why current + * strategy handles such requests to the whole injected context repaint and skips them. + *

+ * It's assumed that corresponding repainting is performed during editor's markup model updates triggered by injected + * context processing. + * + * @author Denis Zhdanov + * @since 6/17/11 11:16 AM + */ +public class InjectedAwareEditorRepaintStrategy implements EditorRepaintStrategy { + + @Override + public TextRange adjustHighlighterRegion(@NotNull EditorEx editor, int startOffset, int endOffset) { + return isInjectedContext(editor, startOffset, endOffset) ? null : new TextRange(startOffset, endOffset); + } + + private static boolean isInjectedContext(@NotNull EditorEx editor, int startOffset, int endOffset) { + final Project project = editor.getProject(); + if (project == null) { + return false; + } + final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); + final PsiFile psiFile = documentManager.getCachedPsiFile(editor.getDocument()); + if (psiFile == null) { + return false; + } + + final List injectedDocuments = InjectedLanguageUtil.getCachedInjectedDocuments(psiFile); + for (DocumentWindow injectedDocument : injectedDocuments) { + for (RangeMarker rangeMarker : injectedDocument.getHostRanges()) { + if (Math.max(rangeMarker.getStartOffset(), startOffset) <= Math.min(rangeMarker.getEndOffset(), endOffset)) { + return true; + } + } + } + return false; + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 47e01bbe9a9d..d1505e61a566 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -54,6 +54,7 @@ import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces; import com.intellij.openapi.editor.impl.softwrap.SoftWrapDrawingType; import com.intellij.openapi.editor.impl.softwrap.SoftWrapHelper; import com.intellij.openapi.editor.markup.*; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory; import com.intellij.openapi.ide.CopyPasteManager; @@ -1312,22 +1313,33 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi return line * getLineHeight(); } - public void repaint(int startOffset, int endOffset) { + public void repaint(final int startOffset, final int endOffset) { if (!isShowing() || myScrollPane == null || myDocument.isInBulkUpdate()) { return; } + int startOffsetToUse = startOffset; + int endOffsetToUse = endOffset; assertIsDispatchThread(); - if (endOffset > myDocument.getTextLength()) { - endOffset = myDocument.getTextLength(); + if (endOffsetToUse > myDocument.getTextLength()) { + endOffsetToUse = myDocument.getTextLength(); + } + + for (EditorRepaintStrategy repaintStrategy : Extensions.getExtensions(EditorRepaintStrategy.EP_NAME)) { + final TextRange range = repaintStrategy.adjustHighlighterRegion(this, startOffsetToUse, endOffsetToUse); + if (range == null) { + return; + } + startOffsetToUse = range.getStartOffset(); + endOffsetToUse = range.getEndOffset(); } // We do repaint in case of equal offsets because there is a possible case that there is a soft wrap at the same offset and // it does occupy particular amount of visual space that may be necessary to repaint. - if (startOffset <= endOffset) { - int startLine = myDocument.getLineNumber(startOffset); - int endLine = myDocument.getLineNumber(endOffset); + if (startOffsetToUse <= endOffsetToUse) { + int startLine = myDocument.getLineNumber(startOffsetToUse); + int endLine = myDocument.getLineNumber(endOffsetToUse); repaintLines(startLine, endLine); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorRepaintStrategy.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorRepaintStrategy.java new file mode 100644 index 000000000000..315c7816525f --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorRepaintStrategy.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.impl; + +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Defines contract for the strategy that may adjust/control editor's repainting. + * + * @author Denis Zhdanov + * @since 6/17/11 11:04 AM + */ +public interface EditorRepaintStrategy { + + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.editorRepaintStrategy"); + + /** + * Asks current strategy to adjust (if necessary) target document region repaint request received from the given editor's highlighter. + * + * @param editor target editor + * @param startOffset start offset of the document text range requested to be repainted (inclusive) + * @param endOffset end offset of the document text range requested to be repainted (exclusive) + * @return actual text range to repaint (if any); null as an indication that no further processing + * for the current repaint request should be performed + */ + @Nullable + TextRange adjustHighlighterRegion(@NotNull EditorEx editor, int startOffset, int endOffset); +} diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index f85f02ac8314..55b6c572d603 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -456,6 +456,7 @@ + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index 4b18ededa4d6..7905c54ba756 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -112,6 +112,8 @@ + +