4
* org.eclipse.jdt.internal.ui.text.JavaPairMatcher
6
package org.python.copiedfromeclipsesrc;
8
import java.io.IOException;
9
import java.util.HashMap;
12
import org.eclipse.jface.text.BadLocationException;
13
import org.eclipse.jface.text.IDocument;
14
import org.eclipse.jface.text.IRegion;
15
import org.eclipse.jface.text.Region;
16
import org.eclipse.jface.text.source.ICharacterPairMatcher;
17
import org.python.pydev.core.docutils.DocUtils;
20
* A character pair matcher finds to a character at a certain document offset the matching peer character. It
21
* is the matchers responsibility to define the concepts of "matching" and "peer". The matching process starts
22
* at a given offset. Starting of this offset, the matcher chooses a character close to this offset. The
23
* anchor defines whether the chosen character is left or right of the initial offset. The matcher then
24
* searches for the matching peer character of the chosen character and if it finds one, delivers the minimal
25
* region of the document that contains both characters.
27
* Typical usage of this class is something like the following:
30
PythonPairMatcher matcher = new PythonPairMatcher(PyDoubleClickStrategy.BRACKETS);
31
IRegion region = matcher.match(document, offset);
38
* @author Fabio Zadrozny
39
* @see org.eclipse.jface.text.source.ICharacterPairMatcher
41
public class PythonPairMatcher implements ICharacterPairMatcher {
43
protected char[] fPairs;
45
protected IDocument fDocument;
47
protected int fOffset;
49
protected int fStartPos;
51
protected int fEndPos;
53
protected int fAnchor;
55
protected PythonCodeReader fReader = new PythonCodeReader();
58
* Constructor which accepts an array of array of characters you want to interpreted as pairs.
60
* Most commonly, you'll simply use STANDARD_PYTHON_PAIRS.
62
* @param pairs an array of characters to be interprested as pairs; the array size must be a multiple of
63
* two, and the first element of the "pair" must be the beginning brace, and the "second"
64
* element of the pair must be the ending brace. For example, pairs[0] = '(', pairs[1] = ')'
66
public PythonPairMatcher(char[] pairs) {
71
* Match the brace specified by the arguments and return the region.
73
* @param document the document in which to search
74
* @param offset the offset where the brace is
75
* @return the region describing the
76
* @see org.eclipse.jface.text.source.ICharacterPairMatcher#match(org.eclipse.jface.text.IDocument, int)
78
public IRegion match(IDocument document, int offset) {
87
if (fDocument != null && matchPairsAt() && fStartPos != fEndPos)
88
return new Region(fStartPos, fEndPos - fStartPos + 1);
96
* @see org.eclipse.jface.text.source.ICharacterPairMatcher#getAnchor()
98
public int getAnchor() {
105
* @see org.eclipse.jface.text.source.ICharacterPairMatcher#dispose()
107
public void dispose() {
114
* @see org.eclipse.jface.text.source.ICharacterPairMatcher#clear()
116
public void clear() {
117
if (fReader != null) {
120
} catch (IOException x) {
126
protected boolean matchPairsAt() {
129
int pairIndex1 = fPairs.length;
130
int pairIndex2 = fPairs.length;
135
// get the chars preceding and following the start position
138
char prevChar = fDocument.getChar(Math.max(fOffset - 1, 0));
139
// modified behavior for http://dev.eclipse.org/bugs/show_bug.cgi?id=16879
140
// char nextChar= fDocument.getChar(fOffset);
142
// search for opening peer character next to the activation point
143
for (i = 0; i < fPairs.length; i = i + 2) {
144
// if (nextChar == fPairs[i]) {
145
// fStartPos= fOffset;
148
if (prevChar == fPairs[i]) {
149
fStartPos = fOffset - 1;
154
// search for closing peer character next to the activation point
155
for (i = 1; i < fPairs.length; i = i + 2) {
156
if (prevChar == fPairs[i]) {
157
fEndPos = fOffset - 1;
160
// else if (nextChar == fPairs[i]) {
168
fStartPos = searchForOpeningPeer(fEndPos, fPairs[pairIndex2 - 1], fPairs[pairIndex2],
174
} else if (fStartPos > -1) {
176
fEndPos = searchForClosingPeer(fStartPos, fPairs[pairIndex1], fPairs[pairIndex1 + 1],
184
} catch (BadLocationException x) {
191
* If you found an opening peer, you'll want to look for a closing peer.
197
* @return the offset of the closing peer
198
* @throws IOException
200
public int searchForClosingPeer(int offset, char openingPeer, char closingPeer, IDocument document){
202
fReader.configureForwardReader(document, offset + 1, document.getLength(), true, true);
205
int c = fReader.read();
206
while (c != PythonCodeReader.EOF) {
207
if (c == openingPeer && c != closingPeer)
209
else if (c == closingPeer)
213
return fReader.getOffset();
219
} catch (Exception e) {
220
throw new RuntimeException(e);
225
* If you found a closing peer, you'll want to search for an opening peer.
231
* @return the offset of the opening peer
232
* @throws IOException
234
public int searchForOpeningPeer(int offset, char openingPeer, char closingPeer, IDocument document){
237
fReader.configureBackwardReader(document, offset, true, true);
240
int c = fReader.read();
241
while (c != PythonCodeReader.EOF) {
242
if (c == closingPeer && c != openingPeer)
244
else if (c == openingPeer)
248
return fReader.getOffset();
254
} catch (Exception e) {
255
throw new RuntimeException(e);
259
public int searchForAnyOpeningPeer(int offset, IDocument document) {
261
fReader.configureBackwardReader(document, offset, true, true);
263
Map<Character, Integer> stack = new HashMap<Character, Integer>();
265
for (int i = 0; i < fPairs.length; i++) {
267
stack.put(fPairs[i], 1);
271
int c = fReader.read();
272
while (c != PythonCodeReader.EOF) {
273
if (c == ')' || c == ']' || c == '}' ){
274
char peer = DocUtils.getPeer((char)c);
275
Integer iStack = stack.get((char)peer);
277
stack.put(peer, iStack);
279
}else if (c == '(' || c == '[' || c == '{'){
280
Integer iStack = stack.get((char)c);
282
stack.put((char) c, iStack);
285
return fReader.getOffset();
294
} catch (Exception e) {
295
throw new RuntimeException(e);