summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDeepak Azad2012-03-11 18:48:38 (EDT)
committer Markus Keller2012-03-11 18:48:38 (EDT)
commitab31f1a2507f1497a0f78a48fe2faaed037040c4 (patch)
treebd315d541244904f780a253efddebf0e3828fadb
parent72d64a944d28d118c91a21fbd05c9b7a3febe8c5 (diff)
downloadeclipse.platform.text-ab31f1a2507f1497a0f78a48fe2faaed037040c4.zip
eclipse.platform.text-ab31f1a2507f1497a0f78a48fe2faaed037040c4.tar.gz
eclipse.platform.text-ab31f1a2507f1497a0f78a48fe2faaed037040c4.tar.bz2
Bug 372128: [syntax highlighting] "Highlight enclosing brackets" hasv20120311-2248
massive performance problems
-rw-r--r--org.eclipse.jface.text/src/org/eclipse/jface/text/source/DefaultCharacterPairMatcher.java242
-rw-r--r--org.eclipse.jface.text/src/org/eclipse/jface/text/source/ICharacterPairMatcherExtension.java44
-rw-r--r--org.eclipse.jface.text/src/org/eclipse/jface/text/source/MatchingCharacterPainter.java200
3 files changed, 424 insertions, 62 deletions
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/DefaultCharacterPairMatcher.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/DefaultCharacterPairMatcher.java
index 4983562..318fa54 100644
--- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/DefaultCharacterPairMatcher.java
+++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/DefaultCharacterPairMatcher.java
@@ -9,9 +9,6 @@
* Christian Plesner Hansen (plesner@quenta.org) - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.text.source;
-import java.util.HashSet;
-import java.util.Set;
-
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.text.BadLocationException;
@@ -132,38 +129,94 @@ public class DefaultCharacterPairMatcher implements ICharacterPairMatcher, IChar
if (document == null || offset < 0 || offset > document.getLength())
return null;
- int start;
- int end;
- if (length >= 0) {
- start= offset;
- end= offset + length;
- } else {
- end= offset;
- start= offset + length;
+ //maybe a bracket is selected
+ IRegion region= match(document, offset, length);
+ fAnchor= ICharacterPairMatcher.LEFT; //always set the anchor to LEFT
+ if (region != null) {
+ return region;
}
- int sourceCaretOffset= offset + length;
- int adjustment= getOffsetAdjustment(document, sourceCaretOffset, length);
- sourceCaretOffset+= adjustment;
+ //bracket is not selected
+ try {
+ final String partition1= TextUtilities.getContentType(document, fPartitioning, offset, false);
+ final DocumentPartitionAccessor partDoc= new DocumentPartitionAccessor(document, fPartitioning, partition1);
+ return findEnclosingPeers(document, partDoc, offset, length, 0, document.getLength());
+ } catch (BadLocationException ble) {
+ fAnchor= -1;
+ return null;
+ }
+ }
+
+ /**
+ * @see org.eclipse.jface.text.source.ICharacterPairMatcherExtension#isMatchedChar(char)
+ * @since 3.8
+ */
+ public boolean isMatchedChar(char ch) {
+ return fPairs.contains(ch);
+ }
+
+ /**
+ * @see org.eclipse.jface.text.source.ICharacterPairMatcherExtension#isMatchedChar(char,
+ * org.eclipse.jface.text.IDocument, int)
+ * @since 3.8
+ */
+ public boolean isMatchedChar(char ch, IDocument document, int offset) {
+ return isMatchedChar(ch);
+ }
+
+ /**
+ * @see org.eclipse.jface.text.source.ICharacterPairMatcherExtension#isRecomputationOfEnclosingPairRequired(org.eclipse.jface.text.IDocument,
+ * org.eclipse.jface.text.IRegion, org.eclipse.jface.text.IRegion)
+ * @since 3.8
+ */
+ public boolean isRecomputationOfEnclosingPairRequired(IDocument document, IRegion currentSelection, IRegion previousSelection) {
+ int previousStartOffset= previousSelection.getOffset();
+ int currentStartOffset= currentSelection.getOffset();
+ int previousEndOffset= previousStartOffset + previousSelection.getLength();
+ int currentEndOffset= currentStartOffset + currentSelection.getLength();
try {
- for (int offset1= sourceCaretOffset; offset1 >= 0; offset1--) {
- char prevChar= document.getChar(Math.max(offset1 - 1, 0));
- if (fPairs.contains(prevChar) && fPairs.isStartCharacter(prevChar)) {
- IRegion match= performMatch(document, offset1);
- if (match != null) {
- int matchOffset= match.getOffset();
- int matchLength= match.getLength();
- if ((matchOffset <= start) && (matchOffset + matchLength > start) && (matchOffset < end) && (matchOffset + matchLength >= end)) {
- return match;
- }
- }
+ String prevEndContentType= TextUtilities.getContentType(document, fPartitioning, previousEndOffset, false);
+ String currEndContentType= TextUtilities.getContentType(document, fPartitioning, currentEndOffset, false);
+ if (!prevEndContentType.equals(currEndContentType))
+ return true;
+
+ String prevStartContentType= TextUtilities.getContentType(document, fPartitioning, previousEndOffset, false);
+ String currStartContentType= TextUtilities.getContentType(document, fPartitioning, currentEndOffset, false);
+ if (!prevStartContentType.equals(currStartContentType))
+ return true;
+
+ int start;
+ int end;
+ if (currentEndOffset > previousEndOffset) {
+ start= previousEndOffset;
+ end= currentEndOffset;
+ } else {
+ start= currentEndOffset;
+ end= previousEndOffset;
+ }
+ for (int i= start; i < end; i++) {
+ if (isMatchedChar(document.getChar(i))) {
+ return true;
}
}
- } catch (BadLocationException ble) {
- return null;
+
+ if (currentStartOffset > previousStartOffset) {
+ start= previousStartOffset;
+ end= currentStartOffset;
+ } else {
+ start= currentStartOffset;
+ end= previousStartOffset;
+ }
+ for (int i= start; i < end; i++) {
+ if (isMatchedChar(document.getChar(i))) {
+ return true;
+ }
+ }
+ } catch (BadLocationException e) {
+ //do nothing
}
- return null;
+ return false;
}
/**
@@ -261,6 +314,106 @@ public class DefaultCharacterPairMatcher implements ICharacterPairMatcher, IChar
return -1;
}
+ /*
+ * Performs the actual work of finding enclosing peer characters for #findEnclosingPeerCharacters(IDocument, int, int).
+ */
+ private IRegion findEnclosingPeers(IDocument document, DocumentPartitionAccessor doc, int offset, int length, int lowerBoundary, int upperBoundary) throws BadLocationException {
+ char[] pairs= fPairs.fPairs;
+
+ int start;
+ int end;
+ if (length >= 0) {
+ start= offset;
+ end= offset + length;
+ } else {
+ end= offset;
+ start= offset + length;
+ }
+
+ boolean lowerFound= false;
+ boolean upperFound= false;
+ int[][] counts= new int[pairs.length][2];
+ int pos1= doc.getNextPosition(start, false);
+ int pos2= start;
+
+ while ((pos1 >= lowerBoundary && !lowerFound) || (pos2 < upperBoundary && !upperFound)) {
+ for (int i= 0; i < counts.length; i++) {
+ counts[i][0]= counts[i][1]= 0;
+ }
+
+ outer1: while (pos1 >= lowerBoundary && !lowerFound) {
+ final char c= doc.getChar(pos1);
+ int i= getCharacterIndex(c, document, pos1);
+ if (i != -1 && doc.inPartition(pos1)) {
+ if (i % 2 == 0) {
+ counts[i / 2][0]--; //start
+ } else {
+ counts[i / 2][0]++; //end
+ }
+ for (int j= 0; j < counts.length; j++) {
+ if (counts[j][0] == -1) {
+ lowerFound= true;
+ break outer1;
+ }
+ }
+ }
+ pos1= doc.getNextPosition(pos1, false);
+ }
+
+ outer2: while (pos2 < upperBoundary && !upperFound) {
+ final char c= doc.getChar(pos2);
+ int i= getCharacterIndex(c, document, pos2);
+ if (i != -1 && doc.inPartition(pos2)) {
+ if (i % 2 == 0) {
+ counts[i / 2][1]++; //start
+ } else {
+ counts[i / 2][1]--; //end
+ }
+ for (int j= 0; j < counts.length; j++) {
+ if (counts[j][1] == -1 && counts[j][0] == -1) {
+ upperFound= true;
+ break outer2;
+ }
+ }
+ }
+ pos2= doc.getNextPosition(pos2, true);
+ }
+
+ if (pos1 > start || pos2 < end) {
+ //match inside selection => discard
+ pos1= doc.getNextPosition(pos1, false);
+ pos2= doc.getNextPosition(pos2, true);
+ lowerFound= false;
+ upperFound= false;
+ }
+ }
+ pos2++;
+ if (pos1 < lowerBoundary || pos2 > upperBoundary)
+ return null;
+ return new Region(pos1, pos2 - pos1);
+ }
+
+ /**
+ * Determines the index of the character in the char array passed to the constructor of the pair
+ * matcher.
+ *
+ * @param ch the character
+ * @param document the document
+ * @param offset the offset in document
+ * @return the index of the character in the char array passed to the constructor of the pair
+ * matcher, and -1 if the character is not one of the matched characters
+ * @since 3.8
+ */
+ private int getCharacterIndex(char ch, IDocument document, int offset) {
+ char[] pairs= fPairs.fPairs;
+ for (int i= 0; i < pairs.length; i++) {
+ if (pairs[i] == ch && isMatchedChar(ch, document, offset)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
/* @see ICharacterPairMatcher#getAnchor() */
public int getAnchor() {
return fAnchor;
@@ -285,6 +438,7 @@ public class DefaultCharacterPairMatcher implements ICharacterPairMatcher, IChar
private final IDocument fDocument;
private final String fPartitioning, fPartition;
private ITypedRegion fCachedPartition;
+ private int fLength;
/**
* Creates a new partitioned document for the specified document.
@@ -298,6 +452,7 @@ public class DefaultCharacterPairMatcher implements ICharacterPairMatcher, IChar
fDocument= doc;
fPartitioning= partitioning;
fPartition= partition;
+ fLength= doc.getLength();
}
/**
@@ -338,7 +493,7 @@ public class DefaultCharacterPairMatcher implements ICharacterPairMatcher, IChar
}
/**
- * Returns the next position to query in the search. The position
+ * Returns the next position to query in the search. The position
* is not guaranteed to be in this document's partition.
*
* @param pos an offset within the document
@@ -347,8 +502,7 @@ public class DefaultCharacterPairMatcher implements ICharacterPairMatcher, IChar
*/
public int getNextPosition(int pos, boolean searchForward) {
final ITypedRegion partition= getPartition(pos);
- if (partition == null) return simpleIncrement(pos, searchForward);
- if (fPartition.equals(partition.getType()))
+ if (partition == null || fPartition.equals(partition.getType()))
return simpleIncrement(pos, searchForward);
if (searchForward) {
int end= partition.getOffset() + partition.getLength();
@@ -376,7 +530,7 @@ public class DefaultCharacterPairMatcher implements ICharacterPairMatcher, IChar
*/
private ITypedRegion getPartition(int pos) {
if (fCachedPartition == null || !contains(fCachedPartition, pos)) {
- Assert.isTrue(pos >= 0 && pos <= fDocument.getLength());
+ Assert.isTrue(pos >= 0 && pos <= fLength);
try {
fCachedPartition= TextUtilities.getPartition(fDocument, fPartitioning, pos, false);
} catch (BadLocationException e) {
@@ -405,28 +559,18 @@ public class DefaultCharacterPairMatcher implements ICharacterPairMatcher, IChar
}
/**
- * Returns true if the specified character pair occurs in one
- * of the character pairs.
- *
+ * Returns true if the specified character occurs in one of the character pairs.
+ *
* @param c a character
* @return true exactly if the character occurs in one of the pairs
*/
public boolean contains(char c) {
- return getAllCharacters().contains(new Character(c));
- }
-
- private Set/*<Character>*/ fCharsCache= null;
- /**
- * @return A set containing all characters occurring in character pairs.
- */
- private Set/*<Character>*/ getAllCharacters() {
- if (fCharsCache == null) {
- Set/*<Character>*/ set= new HashSet/*<Character>*/();
- for (int i= 0; i < fPairs.length; i++)
- set.add(new Character(fPairs[i]));
- fCharsCache= set;
+ char[] pairs= fPairs;
+ for (int i= 0, n= pairs.length; i < n; i++) {
+ if (c == pairs[i])
+ return true;
}
- return fCharsCache;
+ return false;
}
/**
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/ICharacterPairMatcherExtension.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/ICharacterPairMatcherExtension.java
index ef87038..fb64f42 100644
--- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/ICharacterPairMatcherExtension.java
+++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/ICharacterPairMatcherExtension.java
@@ -49,4 +49,48 @@ public interface ICharacterPairMatcherExtension {
* enclosing pair
*/
IRegion findEnclosingPeerCharacters(IDocument document, int offset, int length);
+
+ /**
+ * Checks whether the character is one of the characters matched by the pair matcher.
+ *
+ * @param ch the character
+ * @return <code>true</code> if the the character is one of the characters matched by the pair
+ * matcher, and <code>false</code> otherwise
+ */
+ boolean isMatchedChar(char ch);
+
+ /**
+ * Checks whether the character is one of the characters matched by the pair matcher.
+ *
+ * <p>
+ * Clients can use this method to handle characters which may have special meaning in some
+ * situations. E.g. in Java, '<' is used as an angular bracket and as well as less-than operator.
+ * </p>
+ *
+ * @param ch the character
+ * @param document the document
+ * @param offset the offset in document
+ * @return <code>true</code> if the the character is one of the characters matched by the pair
+ * matcher, and <code>false</code> otherwise
+ */
+ boolean isMatchedChar(char ch, IDocument document, int offset);
+
+ /**
+ * Computes whether a client needs to recompute the enclosing pair after a selection change in
+ * the document.
+ *
+ * <p>
+ * This is intended to be a quick test to determine whether a re-computation of the enclosing pair is
+ * required, as the re-computation after each selection change via a
+ * {@link #findEnclosingPeerCharacters(IDocument, int, int)} call can be expensive for some
+ * clients.
+ * </p>
+ *
+ * @param document the document to work on
+ * @param currentSelection the current selection in the document
+ * @param previousSelection the previous selection in the document
+ * @return <code>true</code> if the enclosing pair needs to be recomputed, <code>false</code>
+ * otherwise
+ */
+ boolean isRecomputationOfEnclosingPairRequired(IDocument document, IRegion currentSelection, IRegion previousSelection);
}
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/MatchingCharacterPainter.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/MatchingCharacterPainter.java
index f32f1a0..4b416d2 100644
--- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/MatchingCharacterPainter.java
+++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/MatchingCharacterPainter.java
@@ -20,21 +20,27 @@ import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IPaintPositionManager;
import org.eclipse.jface.text.IPainter;
import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextInputListener;
+import org.eclipse.jface.text.ITextListener;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextEvent;
/**
- * Highlights the peer character matching the character near the caret position.
- * This painter can be configured with an
- * {@link org.eclipse.jface.text.source.ICharacterPairMatcher}.
+ * Highlights the peer character matching the character near the caret position, or a pair of peer
+ * characters enclosing the caret position. This painter can be configured with an
+ * {@link org.eclipse.jface.text.source.ICharacterPairMatcher} or an
+ * {@link org.eclipse.jface.text.source.ICharacterPairMatcherExtension}.
* <p>
- * Clients instantiate and configure object of this class.</p>
- *
+ * Clients instantiate and configure an object of this class.
+ * </p>
+ *
* @since 2.1
*/
public final class MatchingCharacterPainter implements IPainter, PaintListener {
@@ -55,13 +61,62 @@ public final class MatchingCharacterPainter implements IPainter, PaintListener {
private Position fPairPosition= new Position(0, 0);
/** The anchor indicating whether the character is left or right of the caret */
private int fAnchor;
- /** Whether to highlight enclosing peer characters or not. */
- private boolean fHighlightEnclosingPeerCharcters;
- /** Whether to highlight the character at caret location or not. */
+
+ /**
+ * Whether to highlight enclosing peer characters or not.
+ *
+ * @since 3.8
+ */
+ private boolean fHighlightEnclosingPeerCharacters;
+
+ /**
+ * Whether to highlight the character at caret location or not.
+ *
+ * @since 3.8
+ */
private boolean fHighlightCharacterAtCaretLocation;
- /** Whether a character is present at caret location or not. */
+
+ /**
+ * Whether a character is present at caret location or not.
+ *
+ * @since 3.8
+ */
private boolean fCharacterPresentAtCaretLocation;
+ /**
+ * The document this painter is associated with.
+ *
+ * @since 3.8
+ */
+ private IDocument fDocument;
+
+ /**
+ * The previous selection, used to determine the need for computing enclosing brackets.
+ *
+ * @since 3.8
+ */
+ private IRegion fPreviousSelection;
+
+ /**
+ * Previous length of the document this painter is associated with.
+ *
+ * @since 3.8
+ */
+ private int fPreviousLengthOfDocument;
+
+ /**
+ * Whether the input document has been replaced or not.
+ *
+ * @since 3.8
+ */
+ private boolean fDocumentChanged;
+
+ /**
+ * The text viewer change listener.
+ *
+ * @since 3.8
+ */
+ private TextListener fTextListener;
/**
* Creates a new MatchingCharacterPainter for the given source viewer using the given character
@@ -75,6 +130,7 @@ public final class MatchingCharacterPainter implements IPainter, PaintListener {
fSourceViewer= sourceViewer;
fMatcher= matcher;
fTextWidget= sourceViewer.getTextWidget();
+ fDocument= fSourceViewer.getDocument();
}
/**
@@ -95,7 +151,8 @@ public final class MatchingCharacterPainter implements IPainter, PaintListener {
* @since 3.8
*/
public void setHighlightEnclosingPeerCharacters(boolean highlightEnclosingPeerCharcters) {
- fHighlightEnclosingPeerCharcters= highlightEnclosingPeerCharcters;
+ fHighlightEnclosingPeerCharacters= highlightEnclosingPeerCharcters;
+ installUninstallTextListener(highlightEnclosingPeerCharcters);
}
/**
@@ -112,6 +169,10 @@ public final class MatchingCharacterPainter implements IPainter, PaintListener {
*/
public void dispose() {
if (fMatcher != null) {
+ if (fMatcher instanceof ICharacterPairMatcherExtension && fTextListener != null) {
+ installUninstallTextListener(false);
+ }
+
fMatcher.clear();
fMatcher= null;
}
@@ -185,7 +246,7 @@ public final class MatchingCharacterPainter implements IPainter, PaintListener {
offset -= region.getOffset();
}
- if (fHighlightCharacterAtCaretLocation || (fHighlightEnclosingPeerCharcters && !fCharacterPresentAtCaretLocation)) {
+ if (fHighlightCharacterAtCaretLocation || (fHighlightEnclosingPeerCharacters && !fCharacterPresentAtCaretLocation)) {
draw(gc, offset, 1);
draw(gc, offset + length - 1, 1);
} else {
@@ -262,7 +323,7 @@ public final class MatchingCharacterPainter implements IPainter, PaintListener {
*/
public void paint(int reason) {
- IDocument document= fSourceViewer.getDocument();
+ IDocument document= fDocument;
if (document == null) {
deactivate(false);
return;
@@ -276,7 +337,28 @@ public final class MatchingCharacterPainter implements IPainter, PaintListener {
ICharacterPairMatcherExtension matcher= (ICharacterPairMatcherExtension)fMatcher;
pair= matcher.match(document, selection.getOffset(), selection.getLength());
characterPresentAtCaretLocation= (pair != null);
- if (pair == null && fHighlightEnclosingPeerCharcters) {
+ if (pair == null && fHighlightEnclosingPeerCharacters) {
+
+ int length= document.getLength();
+ boolean lengthChanged= length != fPreviousLengthOfDocument;
+ fPreviousLengthOfDocument= length;
+
+ if (reason != IPainter.CONFIGURATION && !fDocumentChanged && !lengthChanged && selection.equals(fPreviousSelection)) {
+ return;
+ }
+
+ if (reason == IPainter.TEXT_CHANGE) {
+ fPreviousSelection= selection;
+ return;
+ }
+
+ fDocumentChanged= false;
+ if (reason != IPainter.CONFIGURATION && !lengthChanged && fPreviousSelection != null && reason != IPainter.INTERNAL) {
+ if (!matcher.isRecomputationOfEnclosingPairRequired(document, selection, fPreviousSelection)) {
+ fPreviousSelection= selection;
+ return;
+ }
+ }
pair= matcher.findEnclosingPeerCharacters(document, selection.getOffset(), selection.getLength());
}
} else {
@@ -288,6 +370,7 @@ public final class MatchingCharacterPainter implements IPainter, PaintListener {
characterPresentAtCaretLocation= (pair != null);
}
+ fPreviousSelection= selection;
if (pair == null) {
deactivate(true);
return;
@@ -340,4 +423,95 @@ public final class MatchingCharacterPainter implements IPainter, PaintListener {
public void setPositionManager(IPaintPositionManager manager) {
fPaintPositionManager= manager;
}
+
+ /**
+ * Installs or uninstalls the text listener depending on the boolean parameter.
+ *
+ * @param install <code>true</code> to install the text listener, <code>false</code> to uninstall
+ *
+ * @since 3.8
+ */
+ private void installUninstallTextListener(boolean install) {
+ if (!(fMatcher instanceof ICharacterPairMatcherExtension))
+ return;
+
+ if (install) {
+ fTextListener= new TextListener();
+ fSourceViewer.addTextInputListener(fTextListener);
+ fSourceViewer.addTextListener(fTextListener);
+ } else {
+ if (fTextListener != null) {
+ fSourceViewer.removeTextInputListener(fTextListener);
+ fSourceViewer.removeTextListener(fTextListener);
+ fTextListener= null;
+ }
+ }
+ }
+
+ /**
+ * Listens to document changes and if required by those document changes causes a re-computation
+ * of matching characters.
+ *
+ * @since 3.8
+ */
+ private class TextListener implements ITextListener, ITextInputListener {
+
+ /**
+ * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument,
+ * org.eclipse.jface.text.IDocument)
+ */
+ public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
+ //do nothing
+ }
+
+ /**
+ * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument,
+ * org.eclipse.jface.text.IDocument)
+ */
+ public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
+ fDocument= newInput;
+ fDocumentChanged= true;
+ }
+
+ /**
+ * @see org.eclipse.jface.text.ITextListener#textChanged(org.eclipse.jface.text.TextEvent)
+ */
+ public void textChanged(TextEvent event) {
+ if (!fHighlightEnclosingPeerCharacters || !(fMatcher instanceof ICharacterPairMatcherExtension))
+ return;
+
+ String text= event.getText();
+ String replacedText= event.getReplacedText();
+
+ boolean viewerRedrawState= event.getViewerRedrawState();
+ DocumentEvent documentEvent= event.getDocumentEvent();
+ if (documentEvent == null && !viewerRedrawState)
+ return;
+
+ ICharacterPairMatcherExtension matcher= (ICharacterPairMatcherExtension)fMatcher;
+ boolean found= searchForCharacters(text, matcher) || searchForCharacters(replacedText, matcher);
+
+ if (found || (documentEvent == null && viewerRedrawState)) {
+ paint(IPainter.INTERNAL);
+ }
+ }
+
+ /**
+ * Searches for matched characters in the given string.
+ *
+ * @param text the string to search
+ * @param matcher the pair matcher
+ * @return <code>true</code> if a matched character is found, <code>false</code> otherwise
+ */
+ private boolean searchForCharacters(String text, ICharacterPairMatcherExtension matcher) {
+ if (text == null)
+ return false;
+ for (int i= 0; i < text.length(); i++) {
+ if (matcher.isMatchedChar(text.charAt(i))) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
}