1 11 package org.eclipse.jface.text.source; 12 import java.util.HashSet ; 13 import java.util.Set ; 14 15 import org.eclipse.core.runtime.Assert; 16 17 import org.eclipse.jface.text.BadLocationException; 18 import org.eclipse.jface.text.IDocument; 19 import org.eclipse.jface.text.IDocumentExtension3; 20 import org.eclipse.jface.text.IRegion; 21 import org.eclipse.jface.text.ITypedRegion; 22 import org.eclipse.jface.text.Region; 23 import org.eclipse.jface.text.TextUtilities; 24 25 32 public class DefaultCharacterPairMatcher implements ICharacterPairMatcher { 33 34 private int fAnchor= -1; 35 private final CharPairs fPairs; 36 private final String fPartitioning; 37 38 52 public DefaultCharacterPairMatcher(char[] chars, String partitioning) { 53 Assert.isLegal(chars.length % 2 == 0); 54 Assert.isNotNull(partitioning); 55 fPairs= new CharPairs(chars); 56 fPartitioning= partitioning; 57 } 58 59 72 public DefaultCharacterPairMatcher(char[] chars) { 73 this(chars, IDocumentExtension3.DEFAULT_PARTITIONING); 74 } 75 76 77 public IRegion match(IDocument doc, int offset) { 78 if (doc == null || offset < 0 || offset > doc.getLength()) return null; 79 try { 80 return performMatch(doc, offset); 81 } catch (BadLocationException ble) { 82 return null; 83 } 84 } 85 86 89 private IRegion performMatch(IDocument doc, int offset) throws BadLocationException { 90 final char prevChar= doc.getChar(Math.max(offset - 1, 0)); 91 if (!fPairs.contains(prevChar)) return null; 92 final boolean isForward= fPairs.isStartCharacter(prevChar); 93 fAnchor= isForward ? ICharacterPairMatcher.LEFT : ICharacterPairMatcher.RIGHT; 94 final int searchStartPosition= isForward ? offset : offset - 2; 95 final int adjustedOffset= isForward ? offset - 1 : offset; 96 final String partition= TextUtilities.getContentType(doc, fPartitioning, adjustedOffset, false); 97 final DocumentPartitionAccessor partDoc= new DocumentPartitionAccessor(doc, fPartitioning, partition); 98 int endOffset= findMatchingPeer(partDoc, prevChar, fPairs.getMatching(prevChar), 99 isForward, isForward ? doc.getLength() : -1, 100 searchStartPosition); 101 if (endOffset == -1) return null; 102 final int adjustedEndOffset= isForward ? endOffset + 1: endOffset; 103 if (adjustedEndOffset == adjustedOffset) return null; 104 return new Region(Math.min(adjustedOffset, adjustedEndOffset), 105 Math.abs(adjustedEndOffset - adjustedOffset)); 106 } 107 108 120 private int findMatchingPeer(DocumentPartitionAccessor doc, char start, char end, boolean searchForward, int boundary, int startPos) throws BadLocationException { 121 int pos= startPos; 122 while (pos != boundary) { 123 final char c= doc.getChar(pos); 124 if (doc.isMatch(pos, end)) { 125 return pos; 126 } else if (c == start && doc.inPartition(pos)) { 127 pos= findMatchingPeer(doc, start, end, searchForward, boundary, 128 doc.getNextPosition(pos, searchForward)); 129 if (pos == -1) return -1; 130 } 131 pos= doc.getNextPosition(pos, searchForward); 132 } 133 return -1; 134 } 135 136 137 public int getAnchor() { 138 return fAnchor; 139 } 140 141 142 public void dispose() { } 143 144 145 public void clear() { 146 fAnchor= -1; 147 } 148 149 155 private static class DocumentPartitionAccessor { 156 157 private final IDocument fDocument; 158 private final String fPartitioning, fPartition; 159 private ITypedRegion fCachedPartition; 160 161 168 public DocumentPartitionAccessor(IDocument doc, String partitioning, 169 String partition) { 170 fDocument= doc; 171 fPartitioning= partitioning; 172 fPartition= partition; 173 } 174 175 182 public char getChar(int pos) throws BadLocationException { 183 return fDocument.getChar(pos); 184 } 185 186 197 public boolean isMatch(int pos, char end) throws BadLocationException { 198 return getChar(pos) == end && inPartition(pos); 199 } 200 201 208 public boolean inPartition(int pos) { 209 final ITypedRegion partition= getPartition(pos); 210 return partition != null && partition.getType().equals(fPartition); 211 } 212 213 221 public int getNextPosition(int pos, boolean searchForward) { 222 final ITypedRegion partition= getPartition(pos); 223 if (partition == null) return simpleIncrement(pos, searchForward); 224 if (fPartition.equals(partition.getType())) 225 return simpleIncrement(pos, searchForward); 226 if (searchForward) { 227 int end= partition.getOffset() + partition.getLength(); 228 if (pos < end) 229 return end; 230 } else { 231 int offset= partition.getOffset(); 232 if (pos > offset) 233 return offset - 1; 234 } 235 return simpleIncrement(pos, searchForward); 236 } 237 238 private int simpleIncrement(int pos, boolean searchForward) { 239 return pos + (searchForward ? 1 : -1); 240 } 241 242 250 private ITypedRegion getPartition(int pos) { 251 if (fCachedPartition == null || !contains(fCachedPartition, pos)) { 252 Assert.isTrue(pos >= 0 && pos <= fDocument.getLength()); 253 try { 254 fCachedPartition= TextUtilities.getPartition(fDocument, fPartitioning, pos, false); 255 } catch (BadLocationException e) { 256 fCachedPartition= null; 257 } 258 } 259 return fCachedPartition; 260 } 261 262 private static boolean contains(IRegion region, int pos) { 263 int offset= region.getOffset(); 264 return offset <= pos && pos < offset + region.getLength(); 265 } 266 267 } 268 269 272 private static class CharPairs { 273 274 private final char[] fPairs; 275 276 public CharPairs(char[] pairs) { 277 fPairs= pairs; 278 } 279 280 287 public boolean contains(char c) { 288 return getAllCharacters().contains(new Character (c)); 289 } 290 291 private Set fCharsCache= null; 292 295 private Set getAllCharacters() { 296 if (fCharsCache == null) { 297 Set set= new HashSet (); 298 for (int i= 0; i < fPairs.length; i++) 299 set.add(new Character (fPairs[i])); 300 fCharsCache= set; 301 } 302 return fCharsCache; 303 } 304 305 313 public boolean isOpeningCharacter(char c, boolean searchForward) { 314 for (int i= 0; i < fPairs.length; i += 2) { 315 if (searchForward && getStartChar(i) == c) return true; 316 else if (!searchForward && getEndChar(i) == c) return true; 317 } 318 return false; 319 } 320 321 327 public boolean isStartCharacter(char c) { 328 return this.isOpeningCharacter(c, true); 329 } 330 331 337 public char getMatching(char c) { 338 for (int i= 0; i < fPairs.length; i += 2) { 339 if (getStartChar(i) == c) return getEndChar(i); 340 else if (getEndChar(i) == c) return getStartChar(i); 341 } 342 Assert.isTrue(false); 343 return '\0'; 344 } 345 346 private char getStartChar(int i) { 347 return fPairs[i]; 348 } 349 350 private char getEndChar(int i) { 351 return fPairs[i + 1]; 352 } 353 354 } 355 356 } 357 | Popular Tags |