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..ff4fb0a 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,39 +129,24 @@ 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 { - 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; - } - } - } - } + 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; } - return null; } + /** * Computes the adjustment in the start offset for the purpose of finding a matching peer. This @@ -261,6 +243,110 @@ 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= getCharacterType(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= getCharacterType(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 whether the given character is a start character or an end character or none of + * these. + * + *
+ * Clients can override 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. + *
+ * + * @param ch the character + * @param document the document + * @param offset the offset in document + * @return 0 if start character, 1 if end character and -1 if neither a start or an end character + * @since 3.8 + */ + protected int getCharacterType(char ch, IDocument document, int offset) { + char[] pairs= fPairs.fPairs; + for (int i= 0; i < pairs.length; i++) { + if (pairs[i] == ch) { + return i; + } + } + return -1; + } + /* @see ICharacterPairMatcher#getAnchor() */ public int getAnchor() { return fAnchor; @@ -285,6 +371,7 @@ 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 +385,7 @@ fDocument= doc; fPartitioning= partitioning; fPartition= partition; + fLength= doc.getLength(); } /** @@ -338,7 +426,7 @@ } /** - * 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 +435,7 @@ */ 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 +463,7 @@ */ 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 +492,18 @@ } /** - * 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/*ITextStore
instance */
private final ITextStore fModifiableTextStore;