Skip to content

Commit da50c57

Browse files
author
jdf
committed
Fix #1450
1 parent 63ead50 commit da50c57

3 files changed

Lines changed: 140 additions & 111 deletions

File tree

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package processing.app.syntax;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
*
8+
* @author Jonathan Feinberg <jdf@pobox.com>
9+
*
10+
*/
11+
public class Brackets {
12+
private volatile List<Integer> offsets = null;
13+
14+
public void invalidate() {
15+
offsets = null;
16+
}
17+
18+
public int findMatchingBracket(final String text, final int pos) {
19+
if (offsets == null)
20+
parse(text);
21+
// find this bracket
22+
int p;
23+
for (p = 0; p < offsets.size(); p++)
24+
if (offsets.get(p) == pos)
25+
break;
26+
if (p == offsets.size()) {
27+
return -1;
28+
}
29+
final int direction;
30+
final char alpha = text.charAt(offsets.get(p));
31+
final char beta;
32+
switch (alpha) {
33+
case '(':
34+
beta = ')';
35+
direction = 1;
36+
break;
37+
case ')':
38+
beta = '(';
39+
direction = -1;
40+
break;
41+
case '[':
42+
beta = ']';
43+
direction = 1;
44+
break;
45+
case ']':
46+
beta = '[';
47+
direction = -1;
48+
break;
49+
case '{':
50+
beta = '}';
51+
direction = 1;
52+
break;
53+
case '}':
54+
beta = '{';
55+
direction = -1;
56+
break;
57+
default:
58+
System.err.println("Unexpected char " + alpha + " at position " + p);
59+
return -1;
60+
}
61+
int depth = 1;
62+
for (p += direction; p >= 0 && p < offsets.size(); p += direction) {
63+
final int offset = offsets.get(p);
64+
final char c = text.charAt(offset);
65+
if (c == alpha)
66+
depth++;
67+
else if (c == beta)
68+
depth--;
69+
if (depth == 0)
70+
return offset;
71+
}
72+
return -1;
73+
}
74+
75+
int pos;
76+
77+
private void parse(final String text) {
78+
offsets = new ArrayList<Integer>();
79+
final int len = text.length();
80+
for (pos = 0; pos < len; pos++) {
81+
final char c = text.charAt(pos);
82+
if (c == '/' && (pos < len - 1)) {
83+
final char d = text.charAt(++pos);
84+
if (d == '/') {
85+
readComment(text);
86+
} else if (d == '*') {
87+
readMLComment(text);
88+
}
89+
} else if (c == '"' || c == '\'') {
90+
readString(text, c);
91+
} else if (c == '{' || c == '[' || c == '(' || c == '}' || c == ']'
92+
|| c == ')') {
93+
offsets.add(pos);
94+
}
95+
}
96+
}
97+
98+
private void readString(final String text, final char q) {
99+
final int len = text.length();
100+
for (pos++; pos < len; pos++) {
101+
final char c = text.charAt(pos);
102+
if (c == q) {
103+
return;
104+
}
105+
if (c == '\\') {
106+
pos++;
107+
}
108+
}
109+
}
110+
111+
private void readComment(final String text) {
112+
final int len = text.length();
113+
for (pos++; pos < len; pos++)
114+
if (text.charAt(pos) == '\n') {
115+
pos++;
116+
return;
117+
}
118+
}
119+
120+
private void readMLComment(final String text) {
121+
final int len = text.length();
122+
for (pos++; pos < len; pos++) {
123+
final char c = text.charAt(pos);
124+
if (c == '*' && (pos < len - 1)) {
125+
pos++;
126+
final char d = text.charAt(pos);
127+
if (d == '/') {
128+
return;
129+
}
130+
}
131+
}
132+
}
133+
}

app/src/processing/app/syntax/JEditTextArea.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ public void mouseWheelMoved(MouseWheelEvent e) {
129129
}
130130
});
131131
}
132+
133+
private Brackets bracketHelper = new Brackets();
132134

133135
/**
134136
* Inline Input Method Support for Japanese.
@@ -1714,8 +1716,8 @@ protected void updateBracketHighlight(int newCaretPosition)
17141716

17151717
try
17161718
{
1717-
int offset = TextUtilities.findMatchingBracket(
1718-
document,newCaretPosition - 1);
1719+
int offset = bracketHelper.findMatchingBracket(document.getText(0,
1720+
document.getLength()), newCaretPosition - 1);
17191721
if(offset != -1)
17201722
{
17211723
bracketLine = getLineOfOffset(offset);
@@ -1733,6 +1735,8 @@ protected void updateBracketHighlight(int newCaretPosition)
17331735

17341736
protected void documentChanged(DocumentEvent evt)
17351737
{
1738+
bracketHelper.invalidate();
1739+
17361740
DocumentEvent.ElementChange ch =
17371741
evt.getChange(document.getDefaultRootElement());
17381742

@@ -2112,7 +2116,7 @@ private void doDoubleClick(MouseEvent evt, int line,
21122116
return;
21132117

21142118
try {
2115-
int bracket = TextUtilities.findMatchingBracket(document,
2119+
int bracket = bracketHelper.findMatchingBracket(document.getText(0, document.getLength()),
21162120
Math.max(0,dot - 1));
21172121
if (bracket != -1) {
21182122
int mark = getMarkPosition();

app/src/processing/app/syntax/TextUtilities.java

Lines changed: 0 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
package processing.app.syntax;
1111

12-
import javax.swing.text.*;
1312

1413
/**
1514
* Class with several utility functions used by the text area component.
@@ -18,113 +17,6 @@
1817
*/
1918
public class TextUtilities
2019
{
21-
/**
22-
* Returns the offset of the bracket matching the one at the
23-
* specified offset of the document, or -1 if the bracket is
24-
* unmatched (or if the character is not a bracket).
25-
* @param doc The document
26-
* @param offset The offset
27-
* @exception BadLocationException If an out-of-bounds access
28-
* was attempted on the document text
29-
*/
30-
public static int findMatchingBracket(Document doc, int offset)
31-
throws BadLocationException
32-
{
33-
if(doc.getLength() == 0)
34-
return -1;
35-
char c = doc.getText(offset,1).charAt(0);
36-
char cprime; // c` - corresponding character
37-
boolean direction; // true = back, false = forward
38-
39-
switch(c)
40-
{
41-
case '(': cprime = ')'; direction = false; break;
42-
case ')': cprime = '('; direction = true; break;
43-
case '[': cprime = ']'; direction = false; break;
44-
case ']': cprime = '['; direction = true; break;
45-
case '{': cprime = '}'; direction = false; break;
46-
case '}': cprime = '{'; direction = true; break;
47-
default: return -1;
48-
}
49-
50-
int count;
51-
52-
// How to merge these two cases is left as an exercise
53-
// for the reader.
54-
55-
// Go back or forward
56-
if(direction)
57-
{
58-
// Count is 1 initially because we have already
59-
// `found' one closing bracket
60-
count = 1;
61-
62-
// Get text[0,offset-1];
63-
String text = doc.getText(0,offset);
64-
65-
// Scan backwards
66-
for(int i = offset - 1; i >= 0; i--)
67-
{
68-
// If text[i] == c, we have found another
69-
// closing bracket, therefore we will need
70-
// two opening brackets to complete the
71-
// match.
72-
char x = text.charAt(i);
73-
if(x == c)
74-
count++;
75-
76-
// If text[i] == cprime, we have found a
77-
// opening bracket, so we return i if
78-
// --count == 0
79-
else if(x == cprime)
80-
{
81-
if(--count == 0)
82-
return i;
83-
}
84-
}
85-
}
86-
else
87-
{
88-
// Count is 1 initially because we have already
89-
// `found' one opening bracket
90-
count = 1;
91-
92-
// So we don't have to + 1 in every loop
93-
offset++;
94-
95-
// Number of characters to check
96-
int len = doc.getLength() - offset;
97-
98-
// Get text[offset+1,len];
99-
String text = doc.getText(offset,len);
100-
101-
// Scan forwards
102-
for(int i = 0; i < len; i++)
103-
{
104-
// If text[i] == c, we have found another
105-
// opening bracket, therefore we will need
106-
// two closing brackets to complete the
107-
// match.
108-
char x = text.charAt(i);
109-
110-
if(x == c)
111-
count++;
112-
113-
// If text[i] == cprime, we have found an
114-
// closing bracket, so we return i if
115-
// --count == 0
116-
else if(x == cprime)
117-
{
118-
if(--count == 0)
119-
return i + offset;
120-
}
121-
}
122-
}
123-
124-
// Nothing found
125-
return -1;
126-
}
127-
12820
/**
12921
* Locates the start of the word at the specified position.
13022
* @param line The text

0 commit comments

Comments
 (0)