Improved support for comment folding
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / text / PHPPairMatcher.java
1 package net.sourceforge.phpdt.internal.ui.text;
2
3 /*
4  * (c) Copyright IBM Corp. 2000, 2001.
5  * All Rights Reserved.
6  */
7
8 import java.io.IOException;
9
10 import org.eclipse.jface.text.BadLocationException;
11 import org.eclipse.jface.text.IDocument;
12 import org.eclipse.jface.text.IRegion;
13 import org.eclipse.jface.text.Region;
14 import org.eclipse.jface.text.source.ICharacterPairMatcher;
15
16 /**
17  * Helper class for match pairs of characters.
18  */
19 public class PHPPairMatcher implements ICharacterPairMatcher {
20   protected char[] fPairs;
21
22   protected IDocument fDocument;
23
24   protected int fOffset;
25
26   protected int fStartPos;
27
28   protected int fEndPos;
29
30   protected int fAnchor;
31
32   protected PHPCodeReader fReader = new PHPCodeReader();
33
34   public PHPPairMatcher(char[] pairs) {
35     fPairs = pairs;
36   }
37
38   /*
39    * @see org.eclipse.jface.text.source.ICharacterPairMatcher#clear()
40    */
41   public void clear() {
42     if (fReader != null) {
43       try {
44         fReader.close();
45       } catch (IOException x) {
46         // ignore
47       }
48     }
49   }
50
51   public IRegion match(IDocument document, int offset) {
52
53     fOffset = offset;
54
55     if (fOffset < 0)
56       return null;
57
58     fDocument = document;
59
60     if (matchPairsAt() && fStartPos != fEndPos)
61       return new Region(fStartPos, fEndPos - fStartPos + 1);
62
63     return null;
64   }
65
66   public int getAnchor() {
67     return fAnchor;
68   }
69
70   public void dispose() {
71     fDocument = null;
72     if (fReader != null) {
73       try {
74         fReader.close();
75       } catch (IOException x) {
76         // ignore
77       }
78       fReader = null;
79     }
80   }
81
82   protected boolean matchPairsAt() {
83
84     int i;
85     int pairIndex1 = fPairs.length;
86     int pairIndex2 = fPairs.length;
87
88     fStartPos = -1;
89     fEndPos = -1;
90
91     // get the chars preceding and following the start position
92     try {
93
94       char prevChar = fDocument.getChar(Math.max(fOffset - 1, 0));
95       char nextChar = fDocument.getChar(fOffset);
96
97       // search for opening peer character next to the activation point
98       for (i = 0; i < fPairs.length; i = i + 2) {
99         if (nextChar == fPairs[i]) {
100           fStartPos = fOffset;
101           pairIndex1 = i;
102         } else if (prevChar == fPairs[i]) {
103           fStartPos = fOffset - 1;
104           pairIndex1 = i;
105         }
106       }
107
108       // search for closing peer character next to the activation point
109       for (i = 1; i < fPairs.length; i = i + 2) {
110         if (prevChar == fPairs[i]) {
111           fEndPos = fOffset - 1;
112           pairIndex2 = i;
113         } else if (nextChar == fPairs[i]) {
114           fEndPos = fOffset;
115           pairIndex2 = i;
116         }
117       }
118
119       if (fEndPos > -1) {
120         fAnchor = RIGHT;
121         fStartPos = searchForOpeningPeer(fEndPos, fPairs[pairIndex2 - 1], fPairs[pairIndex2], fDocument);
122         if (fStartPos > -1)
123           return true;
124         else
125           fEndPos = -1;
126       } else if (fStartPos > -1) {
127         fAnchor = LEFT;
128         fEndPos = searchForClosingPeer(fStartPos, fPairs[pairIndex1], fPairs[pairIndex1 + 1], fDocument);
129         if (fEndPos > -1)
130           return true;
131         else
132           fStartPos = -1;
133       }
134
135     } catch (BadLocationException x) {
136     } catch (IOException x) {
137     }
138
139     return false;
140   }
141
142   protected int searchForClosingPeer(int offset, int openingPeer, int closingPeer, IDocument document) throws IOException {
143
144     fReader.configureForwardReader(document, offset + 1, document.getLength(), true, true);
145
146     int stack = 1;
147     int c = fReader.read();
148     while (c != PHPCodeReader.EOF) {
149       if (c == openingPeer && c != closingPeer)
150         stack++;
151       else if (c == closingPeer)
152         stack--;
153
154       if (stack == 0)
155         return fReader.getOffset();
156
157       c = fReader.read();
158     }
159
160     return -1;
161   }
162
163   protected int searchForOpeningPeer(int offset, int openingPeer, int closingPeer, IDocument document) throws IOException {
164
165     fReader.configureBackwardReader(document, offset, true, true);
166
167     int stack = 1;
168     int c = fReader.read();
169     while (c != PHPCodeReader.EOF) {
170       if (c == closingPeer && c != openingPeer)
171         stack++;
172       else if (c == openingPeer)
173         stack--;
174
175       if (stack == 0)
176         return fReader.getOffset();
177
178       c = fReader.read();
179     }
180
181     return -1;
182   }
183 }