Lines 9-17
Link Here
|
9 |
* Christian Plesner Hansen (plesner@quenta.org) - initial API and implementation |
9 |
* Christian Plesner Hansen (plesner@quenta.org) - initial API and implementation |
10 |
*******************************************************************************/ |
10 |
*******************************************************************************/ |
11 |
package org.eclipse.jface.text.source; |
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; |
12 |
import org.eclipse.core.runtime.Assert; |
16 |
|
13 |
|
17 |
import org.eclipse.jface.text.BadLocationException; |
14 |
import org.eclipse.jface.text.BadLocationException; |
Lines 132-169
Link Here
|
132 |
if (document == null || offset < 0 || offset > document.getLength()) |
129 |
if (document == null || offset < 0 || offset > document.getLength()) |
133 |
return null; |
130 |
return null; |
134 |
|
131 |
|
135 |
int start; |
132 |
//maybe a bracket is selected |
136 |
int end; |
133 |
IRegion region= match(document, offset, length); |
137 |
if (length >= 0) { |
134 |
fAnchor= ICharacterPairMatcher.LEFT; //always set the anchor to LEFT |
138 |
start= offset; |
135 |
if (region != null) { |
139 |
end= offset + length; |
136 |
return region; |
140 |
} else { |
|
|
141 |
end= offset; |
142 |
start= offset + length; |
143 |
} |
137 |
} |
144 |
|
138 |
|
145 |
int sourceCaretOffset= offset + length; |
139 |
//bracket is not selected |
146 |
int adjustment= getOffsetAdjustment(document, sourceCaretOffset, length); |
|
|
147 |
sourceCaretOffset+= adjustment; |
148 |
|
149 |
try { |
140 |
try { |
150 |
for (int offset1= sourceCaretOffset; offset1 >= 0; offset1--) { |
141 |
final String partition1= TextUtilities.getContentType(document, fPartitioning, offset, false); |
151 |
char prevChar= document.getChar(Math.max(offset1 - 1, 0)); |
142 |
final DocumentPartitionAccessor partDoc= new DocumentPartitionAccessor(document, fPartitioning, partition1); |
152 |
if (fPairs.contains(prevChar) && fPairs.isStartCharacter(prevChar)) { |
143 |
return findEnclosingPeers(document, partDoc, offset, length, 0, document.getLength()); |
153 |
IRegion match= performMatch(document, offset1); |
|
|
154 |
if (match != null) { |
155 |
int matchOffset= match.getOffset(); |
156 |
int matchLength= match.getLength(); |
157 |
if ((matchOffset <= start) && (matchOffset + matchLength > start) && (matchOffset < end) && (matchOffset + matchLength >= end)) { |
158 |
return match; |
159 |
} |
160 |
} |
161 |
} |
162 |
} |
163 |
} catch (BadLocationException ble) { |
144 |
} catch (BadLocationException ble) { |
|
|
145 |
fAnchor= -1; |
164 |
return null; |
146 |
return null; |
165 |
} |
147 |
} |
166 |
return null; |
148 |
} |
|
|
149 |
|
150 |
/** |
151 |
* @see org.eclipse.jface.text.source.ICharacterPairMatcherExtension#isMatchedChar(char) |
152 |
* @since 3.8 |
153 |
*/ |
154 |
public boolean isMatchedChar(char ch) { |
155 |
return fPairs.contains(ch); |
156 |
} |
157 |
|
158 |
/** |
159 |
* @see org.eclipse.jface.text.source.ICharacterPairMatcherExtension#isMatchedChar(char, |
160 |
* org.eclipse.jface.text.IDocument, int) |
161 |
* @since 3.8 |
162 |
*/ |
163 |
public boolean isMatchedChar(char ch, IDocument document, int offset) { |
164 |
return isMatchedChar(ch); |
165 |
} |
166 |
|
167 |
/** |
168 |
* @see org.eclipse.jface.text.source.ICharacterPairMatcherExtension#isRecomputationOfEnclosingPairRequired(org.eclipse.jface.text.IDocument, |
169 |
* org.eclipse.jface.text.IRegion, org.eclipse.jface.text.IRegion) |
170 |
* @since 3.8 |
171 |
*/ |
172 |
public boolean isRecomputationOfEnclosingPairRequired(IDocument document, IRegion currentSelection, IRegion previousSelection) { |
173 |
int previousCaretOffset= previousSelection.getOffset() + previousSelection.getLength(); |
174 |
int currentCaretOffset= currentSelection.getOffset() + currentSelection.getLength(); |
175 |
|
176 |
try { |
177 |
String prevContentType= TextUtilities.getContentType(document, fPartitioning, previousCaretOffset, false); |
178 |
String currContentType= TextUtilities.getContentType(document, fPartitioning, currentCaretOffset, false); |
179 |
|
180 |
if (!prevContentType.equals(currContentType)) |
181 |
return true; |
182 |
|
183 |
int start; |
184 |
int end; |
185 |
if (currentCaretOffset > previousCaretOffset) { |
186 |
start= previousCaretOffset; |
187 |
end= currentCaretOffset; |
188 |
} else { |
189 |
start= currentCaretOffset; |
190 |
end= previousCaretOffset; |
191 |
} |
192 |
for (int i= start; i < end; i++) { |
193 |
if (isMatchedChar(document.getChar(i))) { |
194 |
return true; |
195 |
} |
196 |
} |
197 |
} catch (BadLocationException e) { |
198 |
//do nothing |
199 |
} |
200 |
return false; |
167 |
} |
201 |
} |
168 |
|
202 |
|
169 |
/** |
203 |
/** |
Lines 261-266
Link Here
|
261 |
return -1; |
295 |
return -1; |
262 |
} |
296 |
} |
263 |
|
297 |
|
|
|
298 |
/* |
299 |
* Performs the actual work of finding enclosing peer characters for #findEnclosingPeerCharacters(IDocument, int, int). |
300 |
*/ |
301 |
private IRegion findEnclosingPeers(IDocument document, DocumentPartitionAccessor doc, int offset, int length, int lowerBoundary, int upperBoundary) throws BadLocationException { |
302 |
char[] pairs= fPairs.fPairs; |
303 |
|
304 |
int start; |
305 |
int end; |
306 |
if (length >= 0) { |
307 |
start= offset; |
308 |
end= offset + length; |
309 |
} else { |
310 |
end= offset; |
311 |
start= offset + length; |
312 |
} |
313 |
|
314 |
boolean lowerFound= false; |
315 |
boolean upperFound= false; |
316 |
int[][] counts= new int[pairs.length][2]; |
317 |
int pos1= doc.getNextPosition(start, false); |
318 |
int pos2= start; |
319 |
|
320 |
while ((pos1 >= lowerBoundary && !lowerFound) || (pos2 < upperBoundary && !upperFound)) { |
321 |
for (int i= 0; i < counts.length; i++) { |
322 |
counts[i][0]= counts[i][1]= 0; |
323 |
} |
324 |
|
325 |
outer1: while (pos1 >= lowerBoundary && !lowerFound) { |
326 |
final char c= doc.getChar(pos1); |
327 |
int i= getCharacterIndex(c, document, pos1); |
328 |
if (i != -1 && doc.inPartition(pos1)) { |
329 |
if (i % 2 == 0) { |
330 |
counts[i / 2][0]--; //start |
331 |
} else { |
332 |
counts[i / 2][0]++; //end |
333 |
} |
334 |
for (int j= 0; j < counts.length; j++) { |
335 |
if (counts[j][0] == -1) { |
336 |
lowerFound= true; |
337 |
break outer1; |
338 |
} |
339 |
} |
340 |
} |
341 |
pos1= doc.getNextPosition(pos1, false); |
342 |
} |
343 |
|
344 |
outer2: while (pos2 < upperBoundary && !upperFound) { |
345 |
final char c= doc.getChar(pos2); |
346 |
int i= getCharacterIndex(c, document, pos2); |
347 |
if (i != -1 && doc.inPartition(pos2)) { |
348 |
if (i % 2 == 0) { |
349 |
counts[i / 2][1]++; //start |
350 |
} else { |
351 |
counts[i / 2][1]--; //end |
352 |
} |
353 |
for (int j= 0; j < counts.length; j++) { |
354 |
if (counts[j][1] == -1 && counts[j][0] == -1) { |
355 |
upperFound= true; |
356 |
break outer2; |
357 |
} |
358 |
} |
359 |
} |
360 |
pos2= doc.getNextPosition(pos2, true); |
361 |
} |
362 |
|
363 |
if (pos1 > start || pos2 < end) { |
364 |
//match inside selection => discard |
365 |
pos1= doc.getNextPosition(pos1, false); |
366 |
pos2= doc.getNextPosition(pos2, true); |
367 |
lowerFound= false; |
368 |
upperFound= false; |
369 |
} |
370 |
} |
371 |
pos2++; |
372 |
if (pos1 < lowerBoundary || pos2 > upperBoundary) |
373 |
return null; |
374 |
return new Region(pos1, pos2 - pos1); |
375 |
} |
376 |
|
377 |
/** |
378 |
* Determines the index of the character in the char array passed to the constructor of the pair |
379 |
* matcher. |
380 |
* |
381 |
* @param ch the character |
382 |
* @param document the document |
383 |
* @param offset the offset in document |
384 |
* @return the index of the character in the char array passed to the constructor of the pair |
385 |
* matcher, and -1 if the character is not one of the matched characters. |
386 |
* @since 3.8 |
387 |
*/ |
388 |
private int getCharacterIndex(char ch, IDocument document, int offset) { |
389 |
char[] pairs= fPairs.fPairs; |
390 |
for (int i= 0; i < pairs.length; i++) { |
391 |
if (pairs[i] == ch && isMatchedChar(ch, document, offset)) { |
392 |
return i; |
393 |
} |
394 |
} |
395 |
return -1; |
396 |
} |
397 |
|
264 |
/* @see ICharacterPairMatcher#getAnchor() */ |
398 |
/* @see ICharacterPairMatcher#getAnchor() */ |
265 |
public int getAnchor() { |
399 |
public int getAnchor() { |
266 |
return fAnchor; |
400 |
return fAnchor; |
Lines 285-290
Link Here
|
285 |
private final IDocument fDocument; |
419 |
private final IDocument fDocument; |
286 |
private final String fPartitioning, fPartition; |
420 |
private final String fPartitioning, fPartition; |
287 |
private ITypedRegion fCachedPartition; |
421 |
private ITypedRegion fCachedPartition; |
|
|
422 |
private int fLength; |
288 |
|
423 |
|
289 |
/** |
424 |
/** |
290 |
* Creates a new partitioned document for the specified document. |
425 |
* Creates a new partitioned document for the specified document. |
Lines 298-303
Link Here
|
298 |
fDocument= doc; |
433 |
fDocument= doc; |
299 |
fPartitioning= partitioning; |
434 |
fPartitioning= partitioning; |
300 |
fPartition= partition; |
435 |
fPartition= partition; |
|
|
436 |
fLength= doc.getLength(); |
301 |
} |
437 |
} |
302 |
|
438 |
|
303 |
/** |
439 |
/** |
Lines 338-344
Link Here
|
338 |
} |
474 |
} |
339 |
|
475 |
|
340 |
/** |
476 |
/** |
341 |
* Returns the next position to query in the search. The position |
477 |
* Returns the next position to query in the search. The position |
342 |
* is not guaranteed to be in this document's partition. |
478 |
* is not guaranteed to be in this document's partition. |
343 |
* |
479 |
* |
344 |
* @param pos an offset within the document |
480 |
* @param pos an offset within the document |
Lines 347-354
Link Here
|
347 |
*/ |
483 |
*/ |
348 |
public int getNextPosition(int pos, boolean searchForward) { |
484 |
public int getNextPosition(int pos, boolean searchForward) { |
349 |
final ITypedRegion partition= getPartition(pos); |
485 |
final ITypedRegion partition= getPartition(pos); |
350 |
if (partition == null) return simpleIncrement(pos, searchForward); |
486 |
if (partition == null || fPartition.equals(partition.getType())) |
351 |
if (fPartition.equals(partition.getType())) |
|
|
352 |
return simpleIncrement(pos, searchForward); |
487 |
return simpleIncrement(pos, searchForward); |
353 |
if (searchForward) { |
488 |
if (searchForward) { |
354 |
int end= partition.getOffset() + partition.getLength(); |
489 |
int end= partition.getOffset() + partition.getLength(); |
Lines 376-382
Link Here
|
376 |
*/ |
511 |
*/ |
377 |
private ITypedRegion getPartition(int pos) { |
512 |
private ITypedRegion getPartition(int pos) { |
378 |
if (fCachedPartition == null || !contains(fCachedPartition, pos)) { |
513 |
if (fCachedPartition == null || !contains(fCachedPartition, pos)) { |
379 |
Assert.isTrue(pos >= 0 && pos <= fDocument.getLength()); |
514 |
Assert.isTrue(pos >= 0 && pos <= fLength); |
380 |
try { |
515 |
try { |
381 |
fCachedPartition= TextUtilities.getPartition(fDocument, fPartitioning, pos, false); |
516 |
fCachedPartition= TextUtilities.getPartition(fDocument, fPartitioning, pos, false); |
382 |
} catch (BadLocationException e) { |
517 |
} catch (BadLocationException e) { |
Lines 405-432
Link Here
|
405 |
} |
540 |
} |
406 |
|
541 |
|
407 |
/** |
542 |
/** |
408 |
* Returns true if the specified character pair occurs in one |
543 |
* Returns true if the specified character occurs in one of the character pairs. |
409 |
* of the character pairs. |
544 |
* |
410 |
* |
|
|
411 |
* @param c a character |
545 |
* @param c a character |
412 |
* @return true exactly if the character occurs in one of the pairs |
546 |
* @return true exactly if the character occurs in one of the pairs |
413 |
*/ |
547 |
*/ |
414 |
public boolean contains(char c) { |
548 |
public boolean contains(char c) { |
415 |
return getAllCharacters().contains(new Character(c)); |
549 |
char[] pairs= fPairs; |
416 |
} |
550 |
for (int i= 0, n= pairs.length; i < n; i++) { |
417 |
|
551 |
if (c == pairs[i]) |
418 |
private Set/*<Character>*/ fCharsCache= null; |
552 |
return true; |
419 |
/** |
|
|
420 |
* @return A set containing all characters occurring in character pairs. |
421 |
*/ |
422 |
private Set/*<Character>*/ getAllCharacters() { |
423 |
if (fCharsCache == null) { |
424 |
Set/*<Character>*/ set= new HashSet/*<Character>*/(); |
425 |
for (int i= 0; i < fPairs.length; i++) |
426 |
set.add(new Character(fPairs[i])); |
427 |
fCharsCache= set; |
428 |
} |
553 |
} |
429 |
return fCharsCache; |
554 |
return false; |
430 |
} |
555 |
} |
431 |
|
556 |
|
432 |
/** |
557 |
/** |