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/**/ fCharsCache= null; - /** - * @return A set containing all characters occurring in character pairs. - */ - private Set/**/ getAllCharacters() { - if (fCharsCache == null) { - Set/**/ set= new HashSet/**/(); - 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.text.tests/src/org/eclipse/text/tests/CopyOnWriteTextStoreTest.java b/org.eclipse.text.tests/src/org/eclipse/text/tests/CopyOnWriteTextStoreTest.java index 589aa7b..2fc930e 100644 --- a/org.eclipse.text.tests/src/org/eclipse/text/tests/CopyOnWriteTextStoreTest.java +++ b/org.eclipse.text.tests/src/org/eclipse/text/tests/CopyOnWriteTextStoreTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2008 IBM Corporation and others. + * Copyright (c) 2005, 2012 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -31,7 +31,7 @@ super(new GapTextStore()); } ITextStore getStore() { - return fTextStore; + return (ITextStore)new Accessor(this, CopyOnWriteTextStore.class).get("fTextStore"); } String get() { return get(0, getLength()); @@ -68,7 +68,7 @@ // check that underlying text store is not modifiable boolean failed= false; try { - fText.getStore().replace(0,0,null); + fText.getStore().replace(0, 0, null); } catch (UnsupportedOperationException uoe) { failed= true; } @@ -91,7 +91,7 @@ // check that underlying text store is not modifiable boolean failed= false; try { - fText.getStore().replace(0,0,null); + fText.getStore().replace(0, 0, null); } catch (UnsupportedOperationException uoe) { failed= true; } diff --git a/org.eclipse.text/src/org/eclipse/jface/text/AbstractDocument.java b/org.eclipse.text/src/org/eclipse/jface/text/AbstractDocument.java index a4e5095..9bdd52d 100644 --- a/org.eclipse.text/src/org/eclipse/jface/text/AbstractDocument.java +++ b/org.eclipse.text/src/org/eclipse/jface/text/AbstractDocument.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2012 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -802,9 +802,11 @@ * @see org.eclipse.jface.text.IDocument#getChar(int) */ public char getChar(int pos) throws BadLocationException { - if ((0 > pos) || (pos >= getLength())) + try { + return getStore().get(pos); + } catch (IndexOutOfBoundsException e) { throw new BadLocationException(); - return getStore().get(pos); + } } /* diff --git a/org.eclipse.text/src/org/eclipse/jface/text/CopyOnWriteTextStore.java b/org.eclipse.text/src/org/eclipse/jface/text/CopyOnWriteTextStore.java index 7bb46ee..acbe1e2 100644 --- a/org.eclipse.text/src/org/eclipse/jface/text/CopyOnWriteTextStore.java +++ b/org.eclipse.text/src/org/eclipse/jface/text/CopyOnWriteTextStore.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2010 IBM Corporation and others. + * Copyright (c) 2005, 2012 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -107,7 +107,7 @@ } /** The underlying "real" text store */ - protected ITextStore fTextStore= new StringTextStore(); + private ITextStore fTextStore; /** A modifiable ITextStore instance */ private final ITextStore fModifiableTextStore;