~vil/pydev/upstream

« back to all changes in this revision

Viewing changes to org.python.pydev/src/org/python/copiedfromeclipsesrc/PythonPairMatcher.java

  • Committer: Vladimír Lapáček
  • Date: 2006-08-30 18:38:44 UTC
  • Revision ID: vladimir.lapacek@gmail.com-20060830183844-f4d82c1239a7770a
Initial import of upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * TAKEN FROM 
 
3
 * 
 
4
 * org.eclipse.jdt.internal.ui.text.JavaPairMatcher
 
5
 */
 
6
package org.python.copiedfromeclipsesrc;
 
7
 
 
8
import java.io.IOException;
 
9
import java.util.HashMap;
 
10
import java.util.Map;
 
11
 
 
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;
 
18
 
 
19
/**
 
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.
 
26
 * 
 
27
 * Typical usage of this class is something like the following:
 
28
 * 
 
29
 * @code
 
30
   PythonPairMatcher matcher = new PythonPairMatcher(PyDoubleClickStrategy.BRACKETS);
 
31
   IRegion region = matcher.match(document, offset);
 
32
   if (region != null)
 
33
   {
 
34
     // do something
 
35
   }
 
36
   @endcode
 
37
 * 
 
38
 * @author Fabio Zadrozny
 
39
 * @see org.eclipse.jface.text.source.ICharacterPairMatcher
 
40
 */
 
41
public class PythonPairMatcher implements ICharacterPairMatcher {
 
42
 
 
43
    protected char[] fPairs;
 
44
 
 
45
    protected IDocument fDocument;
 
46
 
 
47
    protected int fOffset;
 
48
 
 
49
    protected int fStartPos;
 
50
 
 
51
    protected int fEndPos;
 
52
 
 
53
    protected int fAnchor;
 
54
 
 
55
    protected PythonCodeReader fReader = new PythonCodeReader();
 
56
 
 
57
    /**
 
58
     * Constructor which accepts an array of array of characters you want to interpreted as pairs.
 
59
     * 
 
60
     * Most commonly, you'll simply use STANDARD_PYTHON_PAIRS.
 
61
     * 
 
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] = ')'
 
65
     */
 
66
    public PythonPairMatcher(char[] pairs) {
 
67
        fPairs = pairs;
 
68
    }
 
69
 
 
70
    /**
 
71
     * Match the brace specified by the arguments and return the region.
 
72
     * 
 
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)
 
77
     */
 
78
    public IRegion match(IDocument document, int offset) {
 
79
 
 
80
        fOffset = offset;
 
81
 
 
82
        if (fOffset < 0)
 
83
            return null;
 
84
 
 
85
        fDocument = document;
 
86
 
 
87
        if (fDocument != null && matchPairsAt() && fStartPos != fEndPos)
 
88
            return new Region(fStartPos, fEndPos - fStartPos + 1);
 
89
 
 
90
        return null;
 
91
    }
 
92
 
 
93
    /*
 
94
     * (non-Javadoc)
 
95
     * 
 
96
     * @see org.eclipse.jface.text.source.ICharacterPairMatcher#getAnchor()
 
97
     */
 
98
    public int getAnchor() {
 
99
        return fAnchor;
 
100
    }
 
101
 
 
102
    /*
 
103
     * (non-Javadoc)
 
104
     * 
 
105
     * @see org.eclipse.jface.text.source.ICharacterPairMatcher#dispose()
 
106
     */
 
107
    public void dispose() {
 
108
        clear();
 
109
        fDocument = null;
 
110
        fReader = null;
 
111
    }
 
112
 
 
113
    /*
 
114
     * @see org.eclipse.jface.text.source.ICharacterPairMatcher#clear()
 
115
     */
 
116
    public void clear() {
 
117
        if (fReader != null) {
 
118
            try {
 
119
                fReader.close();
 
120
            } catch (IOException x) {
 
121
                // ignore
 
122
            }
 
123
        }
 
124
    }
 
125
 
 
126
    protected boolean matchPairsAt() {
 
127
 
 
128
        int i;
 
129
        int pairIndex1 = fPairs.length;
 
130
        int pairIndex2 = fPairs.length;
 
131
 
 
132
        fStartPos = -1;
 
133
        fEndPos = -1;
 
134
 
 
135
        // get the chars preceding and following the start position
 
136
        try {
 
137
 
 
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);
 
141
 
 
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;
 
146
                // pairIndex1= i;
 
147
                // } else
 
148
                if (prevChar == fPairs[i]) {
 
149
                    fStartPos = fOffset - 1;
 
150
                    pairIndex1 = i;
 
151
                }
 
152
            }
 
153
 
 
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;
 
158
                    pairIndex2 = i;
 
159
                }
 
160
                // else if (nextChar == fPairs[i]) {
 
161
                // fEndPos= fOffset;
 
162
                // pairIndex2= i;
 
163
                // }
 
164
            }
 
165
 
 
166
            if (fEndPos > -1) {
 
167
                fAnchor = RIGHT;
 
168
                fStartPos = searchForOpeningPeer(fEndPos, fPairs[pairIndex2 - 1], fPairs[pairIndex2],
 
169
                        fDocument);
 
170
                if (fStartPos > -1)
 
171
                    return true;
 
172
                else
 
173
                    fEndPos = -1;
 
174
            } else if (fStartPos > -1) {
 
175
                fAnchor = LEFT;
 
176
                fEndPos = searchForClosingPeer(fStartPos, fPairs[pairIndex1], fPairs[pairIndex1 + 1],
 
177
                        fDocument);
 
178
                if (fEndPos > -1)
 
179
                    return true;
 
180
                else
 
181
                    fStartPos = -1;
 
182
            }
 
183
 
 
184
        } catch (BadLocationException x) {
 
185
        }
 
186
 
 
187
        return false;
 
188
    }
 
189
 
 
190
    /**
 
191
     * If you found an opening peer, you'll want to look for a closing peer.
 
192
     * 
 
193
     * @param offset
 
194
     * @param openingPeer
 
195
     * @param closingPeer
 
196
     * @param document
 
197
     * @return the offset of the closing peer
 
198
     * @throws IOException
 
199
     */
 
200
    public int searchForClosingPeer(int offset, char openingPeer, char closingPeer, IDocument document){
 
201
        try {
 
202
            fReader.configureForwardReader(document, offset + 1, document.getLength(), true, true);
 
203
 
 
204
            int stack = 1;
 
205
            int c = fReader.read();
 
206
            while (c != PythonCodeReader.EOF) {
 
207
                if (c == openingPeer && c != closingPeer)
 
208
                    stack++;
 
209
                else if (c == closingPeer)
 
210
                    stack--;
 
211
 
 
212
                if (stack == 0)
 
213
                    return fReader.getOffset();
 
214
 
 
215
                c = fReader.read();
 
216
            }
 
217
 
 
218
            return -1;
 
219
        } catch (Exception e) {
 
220
            throw new RuntimeException(e);
 
221
        }
 
222
    }
 
223
 
 
224
    /**
 
225
     * If you found a closing peer, you'll want to search for an opening peer.
 
226
     * 
 
227
     * @param offset
 
228
     * @param openingPeer
 
229
     * @param closingPeer
 
230
     * @param document
 
231
     * @return the offset of the opening peer
 
232
     * @throws IOException
 
233
     */
 
234
    public int searchForOpeningPeer(int offset, char openingPeer, char closingPeer, IDocument document){
 
235
 
 
236
        try {
 
237
                        fReader.configureBackwardReader(document, offset, true, true);
 
238
 
 
239
                        int stack = 1;
 
240
                        int c = fReader.read();
 
241
                        while (c != PythonCodeReader.EOF) {
 
242
                                if (c == closingPeer && c != openingPeer)
 
243
                                        stack++;
 
244
                                else if (c == openingPeer)
 
245
                                        stack--;
 
246
 
 
247
                                if (stack == 0)
 
248
                                        return fReader.getOffset();
 
249
 
 
250
                                c = fReader.read();
 
251
                        }
 
252
 
 
253
                        return -1;
 
254
                } catch (Exception e) {
 
255
                        throw new RuntimeException(e);
 
256
                }
 
257
    }
 
258
 
 
259
    public int searchForAnyOpeningPeer(int offset, IDocument document) {
 
260
        try {
 
261
            fReader.configureBackwardReader(document, offset, true, true);
 
262
            
 
263
            Map<Character, Integer> stack = new HashMap<Character, Integer>();
 
264
            
 
265
            for (int i = 0; i < fPairs.length; i++) {
 
266
                if(i %2 == 0){
 
267
                    stack.put(fPairs[i], 1);
 
268
                }
 
269
            }
 
270
            
 
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);
 
276
                    iStack++;
 
277
                    stack.put(peer, iStack);
 
278
                    
 
279
                }else if (c == '(' || c == '[' || c == '{'){
 
280
                    Integer iStack = stack.get((char)c);
 
281
                    iStack--;
 
282
                    stack.put((char) c, iStack);
 
283
                    
 
284
                    if (iStack == 0){
 
285
                        return fReader.getOffset();
 
286
                    }
 
287
                }
 
288
                
 
289
                
 
290
                c = fReader.read();
 
291
            }
 
292
            
 
293
            return -1;
 
294
        } catch (Exception e) {
 
295
            throw new RuntimeException(e);
 
296
        }
 
297
    }
 
298
}