1 package debugger.gui.debugging;
2
3 import javax.swing.text.*;
4 import java.util.Hashtable;
5 import java.awt.*;
6
7
13
14 class SyntaxDocument extends DefaultStyledDocument {
15 private DefaultStyledDocument doc;
16 private Element rootElement;
17
18 private boolean multiLineComment;
19 private MutableAttributeSet normal;
20 private MutableAttributeSet keyword;
21 private MutableAttributeSet comment;
22 private MutableAttributeSet quote;
23
24 private Hashtable keywords;
25
26 public SyntaxDocument() {
27 doc = this;
28 rootElement = doc.getDefaultRootElement();
29 putProperty(DefaultEditorKit.EndOfLineStringProperty, "\n");
30
31 normal = new SimpleAttributeSet();
32 StyleConstants.setForeground(normal, Color.black);
33
34 comment = new SimpleAttributeSet();
35 StyleConstants.setForeground(comment, Color.gray);
36 StyleConstants.setItalic(comment, true);
37
38 keyword = new SimpleAttributeSet();
39 StyleConstants.setForeground(keyword, Color.blue);
40
41 quote = new SimpleAttributeSet();
42 StyleConstants.setForeground(quote, Color.red);
43
44 Object dummyObject = new Object();
45 keywords = new Hashtable();
46 keywords.put("abstract", dummyObject);
47 keywords.put("boolean", dummyObject);
48 keywords.put("break", dummyObject);
49 keywords.put("byte", dummyObject);
50 keywords.put("byvalue", dummyObject);
51 keywords.put("case", dummyObject);
52 keywords.put("cast", dummyObject);
53 keywords.put("catch", dummyObject);
54 keywords.put("char", dummyObject);
55 keywords.put("class", dummyObject);
56 keywords.put("const", dummyObject);
57 keywords.put("continue", dummyObject);
58 keywords.put("default", dummyObject);
59 keywords.put("do", dummyObject);
60 keywords.put("double", dummyObject);
61 keywords.put("else", dummyObject);
62 keywords.put("extends", dummyObject);
63 keywords.put("false", dummyObject);
64 keywords.put("final", dummyObject);
65 keywords.put("finally", dummyObject);
66 keywords.put("float", dummyObject);
67 keywords.put("for", dummyObject);
68 keywords.put("future", dummyObject);
69 keywords.put("generic", dummyObject);
70 keywords.put("goto", dummyObject);
71 keywords.put("if", dummyObject);
72 keywords.put("implements", dummyObject);
73 keywords.put("import", dummyObject);
74 keywords.put("inner", dummyObject);
75 keywords.put("instanceof", dummyObject);
76 keywords.put("int", dummyObject);
77 keywords.put("interface", dummyObject);
78 keywords.put("long", dummyObject);
79 keywords.put("native", dummyObject);
80 keywords.put("new", dummyObject);
81 keywords.put("null", dummyObject);
82 keywords.put("operator", dummyObject);
83 keywords.put("outer", dummyObject);
84 keywords.put("package", dummyObject);
85 keywords.put("private", dummyObject);
86 keywords.put("protected", dummyObject);
87 keywords.put("public", dummyObject);
88 keywords.put("rest", dummyObject);
89 keywords.put("return", dummyObject);
90 keywords.put("short", dummyObject);
91 keywords.put("static", dummyObject);
92 keywords.put("super", dummyObject);
93 keywords.put("switch", dummyObject);
94 keywords.put("synchronized", dummyObject);
95 keywords.put("this", dummyObject);
96 keywords.put("throw", dummyObject);
97 keywords.put("throws", dummyObject);
98 keywords.put("transient", dummyObject);
99 keywords.put("true", dummyObject);
100 keywords.put("try", dummyObject);
101 keywords.put("var", dummyObject);
102 keywords.put("void", dummyObject);
103 keywords.put("volatile", dummyObject);
104 keywords.put("while", dummyObject);
105 keywords.put("Rule", dummyObject);
106 keywords.put("Phase", dummyObject);
107 keywords.put("Input", dummyObject);
108 keywords.put("Priority", dummyObject);
109 keywords.put("MultiPhase", dummyObject);
110 keywords.put("Macro", dummyObject);
111 }
112
113
116 public void insertString(int offset, String str, AttributeSet a) throws BadLocationException {
117 if (str.equals("{"))
118 str = addMatchingBrace(offset);
119
120 super.insertString(offset, str, a);
121 processChangedLines(offset, str.length());
122 }
123
124
127 public void remove(int offset, int length) throws BadLocationException {
128 super.remove(offset, length);
129 processChangedLines(offset, 0);
130 }
131
132
136 private void processChangedLines(int offset, int length)
137 throws BadLocationException {
138 String content = doc.getText(0, doc.getLength());
139
140
142 int startLine = rootElement.getElementIndex(offset);
143 int endLine = rootElement.getElementIndex(offset + length);
144
145
148 setMultiLineComment(commentLinesBefore(content, startLine));
149
150
152 for (int i = startLine; i <= endLine; i++) {
153 applyHighlighting(content, i);
154 }
155
156
158 if (isMultiLineComment())
159 commentLinesAfter(content, endLine);
160 else
161 highlightLinesAfter(content, endLine);
162 }
163
164
168 private boolean commentLinesBefore(String content, int line) {
169 int offset = rootElement.getElement(line).getStartOffset();
170
171
173 int startDelimiter = lastIndexOf(content, getStartDelimiter(), offset - 2);
174
175 if (startDelimiter < 0)
176 return false;
177
178
180 int endDelimiter = indexOf(content, getEndDelimiter(), startDelimiter);
181
182 if (endDelimiter < offset & endDelimiter != -1)
183 return false;
184
185
187 doc.setCharacterAttributes(startDelimiter, offset - startDelimiter + 1, comment, false);
188 return true;
189 }
190
191
194 private void commentLinesAfter(String content, int line) {
195 int offset = rootElement.getElement(line).getEndOffset();
196
197
199 int endDelimiter = indexOf(content, getEndDelimiter(), offset);
200
201 if (endDelimiter < 0)
202 return;
203
204
206 int startDelimiter = lastIndexOf(content, getStartDelimiter(), endDelimiter);
207
208 if (startDelimiter < 0 || startDelimiter <= offset) {
209 doc.setCharacterAttributes(offset, endDelimiter - offset + 1, comment, false);
210 }
211 }
212
213
216 private void highlightLinesAfter(String content, int line) {
217 int offset = rootElement.getElement(line).getEndOffset();
218
219
221 int startDelimiter = indexOf(content, getStartDelimiter(), offset);
222 int endDelimiter = indexOf(content, getEndDelimiter(), offset);
223
224 if (startDelimiter < 0)
225 startDelimiter = content.length();
226
227 if (endDelimiter < 0)
228 endDelimiter = content.length();
229
230 int delimiter = Math.min(startDelimiter, endDelimiter);
231
232 if (delimiter < offset)
233 return;
234
235
237 int endLine = rootElement.getElementIndex(delimiter);
238
239 for (int i = line + 1; i < endLine; i++) {
240 Element branch = rootElement.getElement(i);
241 Element leaf = doc.getCharacterElement(branch.getStartOffset());
242 AttributeSet as = leaf.getAttributes();
243
244 if (as.isEqual(comment))
245 applyHighlighting(content, i);
246 }
247 }
248
249
252 private void applyHighlighting(String content, int line) {
253 int startOffset = rootElement.getElement(line).getStartOffset();
254 int endOffset = rootElement.getElement(line).getEndOffset() - 1;
255
256 int lineLength = endOffset - startOffset;
257 int contentLength = content.length();
258
259 if (endOffset >= contentLength)
260 endOffset = contentLength - 1;
261
262
265 if (endingMultiLineComment(content, startOffset, endOffset)
266 || isMultiLineComment()
267 || startingMultiLineComment(content, startOffset, endOffset)) {
268 doc.setCharacterAttributes(startOffset, endOffset - startOffset + 1, comment, false);
269 return;
270 }
271
272
274 doc.setCharacterAttributes(startOffset, lineLength, normal, true);
275
276
278 int index = content.indexOf(getSingleLineDelimiter(), startOffset);
279
280 if ((index > -1) && (index < endOffset)) {
281 doc.setCharacterAttributes(index, endOffset - index + 1, comment, false);
282 endOffset = index - 1;
283 }
284
285
287 checkForTokens(content, startOffset, endOffset);
288 }
289
290
296
297
300 private boolean startingMultiLineComment(String content, int startOffset, int endOffset) {
301 int index = indexOf(content, getStartDelimiter(), startOffset);
302
303 if ((index < 0) || (index > endOffset))
304 return false;
305 else {
306 setMultiLineComment(true);
307 return true;
308 }
309 }
310
311
314 private boolean endingMultiLineComment(String content, int startOffset, int endOffset) {
315 int index = indexOf(content, getEndDelimiter(), startOffset);
316
317 if ((index < 0) || (index > endOffset))
318 return false;
319 else {
320 setMultiLineComment(false);
321 return true;
322 }
323 }
324
325
329 private boolean isMultiLineComment() {
330 return multiLineComment;
331 }
332
333 private void setMultiLineComment(boolean value) {
334 multiLineComment = value;
335 }
336
337
340 private void checkForTokens(String content, int startOffset, int endOffset) {
341 while (startOffset <= endOffset) {
342
344 while (isDelimiter(content.substring(startOffset, startOffset + 1))) {
345 if (startOffset < endOffset)
346 startOffset++;
347 else
348 return;
349 }
350
351
353 if (isQuoteDelimiter(content.substring(startOffset, startOffset + 1)))
354 startOffset = getQuoteToken(content, startOffset, endOffset);
355 else
356 startOffset = getOtherToken(content, startOffset, endOffset);
357 }
358 }
359
360
363 private int getQuoteToken(String content, int startOffset, int endOffset) {
364 String quoteDelimiter = content.substring(startOffset, startOffset + 1);
365 String escapeString = getEscapeString(quoteDelimiter);
366
367 int index;
368 int endOfQuote = startOffset;
369
370
372 index = content.indexOf(escapeString, endOfQuote + 1);
373
374 while ((index > -1) && (index < endOffset)) {
375 endOfQuote = index + 1;
376 index = content.indexOf(escapeString, endOfQuote);
377 }
378
379
381 index = content.indexOf(quoteDelimiter, endOfQuote + 1);
382
383 if ((index < 0) || (index > endOffset))
384 endOfQuote = endOffset;
385 else
386 endOfQuote = index;
387
388 doc.setCharacterAttributes(startOffset, endOfQuote - startOffset + 1, quote, false);
389
390 return endOfQuote + 1;
391 }
392
393
396 private int getOtherToken(String content, int startOffset, int endOffset) {
397 int endOfToken = startOffset + 1;
398
399 while (endOfToken <= endOffset) {
400 if (isDelimiter(content.substring(endOfToken, endOfToken + 1)))
401 break;
402
403 endOfToken++;
404 }
405
406 String token = content.substring(startOffset, endOfToken);
407
408 if (isKeyword(token))
409 doc.setCharacterAttributes(startOffset, endOfToken - startOffset, keyword, false);
410
411 return endOfToken + 1;
412 }
413
414
417 private int indexOf(String content, String needle, int offset) {
418 int index;
419
420 while ((index = content.indexOf(needle, offset)) != -1) {
421 String text = getLine(content, index).trim();
422
423 if (text.startsWith(needle) || text.endsWith(needle))
424 break;
425 else
426 offset = index + 1;
427 }
428
429 return index;
430 }
431
432
435 private int lastIndexOf(String content, String needle, int offset) {
436 int index;
437
438 while ((index = content.lastIndexOf(needle, offset)) != -1) {
439 String text = getLine(content, index).trim();
440
441 if (text.startsWith(needle) || text.endsWith(needle))
442 break;
443 else
444 offset = index - 1;
445 }
446
447 return index;
448 }
449
450 private String getLine(String content, int offset) {
451 int line = rootElement.getElementIndex(offset);
452 Element lineElement = rootElement.getElement(line);
453 int start = lineElement.getStartOffset();
454 int end = lineElement.getEndOffset();
455 return content.substring(start, end - 1);
456 }
457
458
461 protected boolean isDelimiter(String character) {
462 String operands = ";:{}()[]+-/%<=>!&|^~*";
463
464 if (Character.isWhitespace(character.charAt(0)) ||
465 operands.indexOf(character) != -1)
466 return true;
467 else
468 return false;
469 }
470
471
474 protected boolean isQuoteDelimiter(String character) {
475 String quoteDelimiters = "\"'";
476
477 if (quoteDelimiters.indexOf(character) < 0)
478 return false;
479 else
480 return true;
481 }
482
483
486 protected boolean isKeyword(String token) {
487 Object o = keywords.get(token);
488
489 return o == null ? false : true;
490 }
491
492
495 protected String getStartDelimiter() {
496 return "/*";
497 }
498
499
502 protected String getEndDelimiter() {
503 return "*/";
504 }
505
506
509 protected String getSingleLineDelimiter() {
510 return "//";
511 }
512
513
516 protected String getEscapeString(String quoteDelimiter) {
517 return "\\" + quoteDelimiter;
518 }
519
520
523 protected String addMatchingBrace(int offset) throws BadLocationException {
524 StringBuffer whiteSpace = new StringBuffer();
525 int line = rootElement.getElementIndex(offset);
526 int i = rootElement.getElement(line).getStartOffset();
527
528 while (true) {
529 String temp = doc.getText(i, 1);
530
531 if (temp.equals(" ") || temp.equals("\t")) {
532 whiteSpace.append(temp);
533 i++;
534 } else
535 break;
536 }
537
538 return "{\n" + whiteSpace.toString() + "\t\n" + whiteSpace.toString() + "}";
539 }
540 }
541
542
543