KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > drjava > model > definitions > reducedmodel > ReducedModelBrace


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2005 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32  *END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.drjava.model.definitions.reducedmodel;
35
36 import java.util.Stack JavaDoc;
37
38 /** Keeps track of the true braces (i.e., "() {}[]"). This reduced sub-model is used to balance braces for both
39  * indenting and highlighting purposes. For example, when the user's caret is immediately after a closing brace,
40  * this allows the DefinitionsPane to produced a highlight extending from the closing brace to its match.
41  * @version $Id: ReducedModelBrace.java 4033 2006-11-16 20:16:51Z rcartwright $
42  * @author JavaPLT
43  */

44 public class ReducedModelBrace extends AbstractReducedModel {
45
46   private ReducedModelControl _parent;
47
48   public ReducedModelBrace(ReducedModelControl parent) {
49     super();
50     _parent = parent;
51   }
52
53   public void insertChar(char ch) {
54     switch(ch) {
55       case '{':
56       case '}':
57       case '[':
58       case ']':
59       case '(':
60       case ')':
61         _insertBrace(String.valueOf(ch));
62       break;
63       default:
64         _insertGap(1);
65       break;
66     }
67   }
68
69
70   /**
71    * Helper function for top level brace insert functions.
72    *
73    * <OL>
74    * <li> at Head: not special case
75    * <li> at Tail: not special case
76    * <li> between two things (offset is 0):
77    * <ol>
78    * <li> insert brace
79    * <li> move next
80    * <li> offset = 0
81    * </ol>
82    * <li> inside gap:
83    * <ol>
84    * <li> shrink gap to size of gap - offset.
85    * <li> insert brace
86    * <li> insert gap the size of offset.
87    * <li> move next twice
88    * <li> offset = 0
89    * </ol>
90    * <li> inside multiple char brace:
91    * <ol>
92    * <li> break
93    * <li> insert brace
94    * </ol>
95    * </OL>
96    * @param text the String type of the brace to insert
97    */

98   private void _insertBrace(String JavaDoc text) {
99     if (_cursor.atStart() || _cursor.atEnd()) {
100       _cursor.insertNewBrace(text); // inserts brace and goes to next
101
}
102     else if (_cursor.current().isGap()) {
103       _cursor.insertBraceToGap(text);
104     }
105
106     else {
107       _cursor.insertNewBrace(text);
108     }
109   }
110
111   /**Inserts a gap between the characters in a multiple character brace.
112     * However, since ReducedModelBrace doesn't keep track of the comment
113     * braces and escape sequences, we just throw an exception since the
114     * condition in insertGap that spawns this method doesn't arise.
115     */

116   protected void insertGapBetweenMultiCharBrace(int length) {
117     throw new RuntimeException JavaDoc("ReducedModelBrace does not keep track of multi-character braces.");
118   }
119
120   /** Updates ReducedModelBrace to reflect cursor movement.
121    * Negative values move left from the cursor, positive values move
122    * right. All functionality has been refactored into TokenList.
123    * @param count indicates the direction and magnitude of cursor movement
124    */

125   public void move(int count) { _cursor.move(count); }
126
127   /** Updates ReducedModelBrace to reflect text deletion.
128    * Negative values mean text left of the cursor, positive values mean
129    * text to the right. All functionality has been refactored into TokenList.
130    */

131   public void delete( int count ) {
132     if (count == 0) return;
133     _cursor.delete(count);
134     return;
135   }
136
137   /** If the current brace is a /, a *, a // or a \n, it's not matchable.
138   * This means it is ignored on balancing and on next/prev brace finding.
139   * All other braces are matchable.
140   */

141   private boolean _isCurrentBraceMatchable() {
142     String JavaDoc type = _cursor.current().getType();
143     return (((type.equals("{")) ||
144              (type.equals("}")) ||
145              (type.equals("(")) ||
146              (type.equals(")")) ||
147              (type.equals("[")) ||
148              (type.equals("]"))) &&
149             (_parent.getStateAtCurrent() == FREE));
150   }
151
152   /**
153    *Returns distance from current location of cursor to the location of the
154    *previous significant brace.
155    *ex. (...|) where | signifies the cursor. previousBrace returns 4 because
156    *it goes to the spot behind the (.
157    * /|* returns this brace since you're in the middle of it and going
158    *backward can find it.
159    */

160   public int previousBrace() {
161     int relDistance;
162     int dist = 0;
163     resetWalkerLocationToCursor();//reset the interface to the comment model
164

165     TokenList.Iterator copyCursor = _cursor._copy();
166     if (!copyCursor.atStart()) {
167       copyCursor.prev();
168     }
169     if (copyCursor.atStart()) {
170       copyCursor.dispose();
171       return -1;
172     }
173     //initialize the size.
174
dist += _cursor.getBlockOffset();
175     relDistance = dist;
176
177     // if we're in the middle of the first brace element, we're
178
// not going to find any previous braces
179

180     while (!copyCursor.atStart()) {
181       if (!copyCursor.current().isGap()) {
182         if (moveWalkerGetState(-relDistance) == FREE) {
183           copyCursor.dispose();
184           return dist + copyCursor.current().getSize();
185         }
186         relDistance = 0;
187       }
188
189       dist += copyCursor.current().getSize();
190       relDistance += copyCursor.current().getSize();
191       copyCursor.prev();
192     }
193     copyCursor.dispose();
194     return -1;
195   }
196
197
198   /**
199    *Goes to the location before the brace. |...( where | is the cursor,
200    *returns three since it is three moves to the location of the (
201    *NOTE: /|* returns the next brace. It does not return this brace because
202    *you are past it.
203    */

204   public int nextBrace() {
205     int relDistance = 0;
206     int dist = 0;
207     TokenList.Iterator copyCursor = _cursor._copy();
208
209     resetWalkerLocationToCursor();
210
211     if ( copyCursor.atStart())
212       copyCursor.next();
213     if (_cursor.getBlockOffset() > 0) {
214       dist = copyCursor.current().getSize() - _cursor.getBlockOffset();
215       relDistance = dist;
216       copyCursor.next();
217     }
218     // there are no braces on the last brace element - it's empty
219
while (!copyCursor.atEnd() ) {
220       if (!copyCursor.current().isGap()) {
221         if (moveWalkerGetState(relDistance) ==
222             FREE) {
223               copyCursor.dispose();
224               return dist;
225             }
226         relDistance = 0;
227       }
228       relDistance += copyCursor.current().getSize();
229       dist += copyCursor.current().getSize();
230       copyCursor.next();
231     }
232     copyCursor.dispose();
233     return -1;
234   }
235
236   /** If the current ReducedToken is an open significant brace and the offset is 0 (i.e., if we're immediately left of
237     * said brace), push the current Brace onto a Stack and iterate forwards, keeping track of the distance covered.
238     * - For every closed significant Brace, if it matches the top of the Stack, pop the Stack. Increase the distance
239     * by the size of the Brace. If the Stack is Empty, we have a balance. Return distance. If the closed Brace does
240     * not match the top of the Stack, return -1; We have an unmatched open Brace at the top of the Stack.
241     * - For every open significant Brace, push onto the Stack. Increase distance by size of the Brace, continue.
242     * - Anything else, increase distance by size of the ReducedToken, continue.
243     */

244   public int balanceForward() {
245     //System.out.println("-------------------------------------------");
246
Stack JavaDoc<ReducedToken> braceStack = new Stack JavaDoc<ReducedToken>();
247     TokenList.Iterator iter = _cursor._copy();
248     resetWalkerLocationToCursor();
249     int relDistance;
250     int distance = 0;
251     if (iter.atStart() || iter.atFirstItem() || !openBraceImmediatelyLeft()) {
252 // System.out.println("openBraceImmediatelyLeft(): "+openBraceImmediatelyLeft());
253
iter.dispose();
254 // System.out.println("! atStart, atFirstItem, or no closed brace");
255
return -1;
256     }
257
258     iter.prev();
259     relDistance = -iter.current().getSize();
260     // here we check to make sure there is an open significant brace
261
// immediately to the left of the cursor
262
if (iter.current().isOpenBrace()) {
263       if (moveWalkerGetState(relDistance) == FREE) {
264         // initialize the stack with the first brace, the one we are balancing
265
braceStack.push(iter.current());
266
267         // reset the walker and iter to where we started
268
iter.next();
269         moveWalkerGetState(-relDistance);
270         relDistance = 0;
271       }
272       else {
273         // the open brace is in a comment or quotation => ignore it
274
iter.dispose();
275 // System.out.println("! state at relative location != FREE");
276
return -1;
277       }
278     }
279     else {
280       // this isn't an open brace => ignore it
281
iter.dispose();
282 // System.out.println("! no open brace to immediate left of cursor");
283
return -1;
284     }
285     // either we get a match and the stack is empty
286
// or we reach the end of a file and haven't found a match
287
// or we have a close brace that doesn't have a match,
288
// so we abort
289
while (!iter.atEnd() && !braceStack.isEmpty()) {
290       if (!iter.current().isGap()) {
291         if (moveWalkerGetState(relDistance) == FREE) {
292               // check for closed brace
293
if (iter.current().isClosedBrace()) {
294                 ReducedToken popped = braceStack.pop();
295                 if (!iter.current().isMatch(popped)) {
296                   iter.dispose();
297 // System.out.println("! encountered closed brace that didn't match");
298
return -1;
299                 }
300               }
301               // otherwise, this must be an open brace
302
else {
303                 braceStack.push(iter.current());
304               }
305             }
306         relDistance = 0;
307       }
308       // no matter what, we always want to increase the distance
309
// by the size of the token we have just gone over
310
distance += iter.current().getSize();
311         relDistance += iter.current().getSize();
312         iter.next();
313     }
314
315     // we couldn't find a match
316
if (!braceStack.isEmpty()) {
317       iter.dispose();
318 // System.out.println("! ran to end of file. distance: " + distance);
319
return -1;
320     }
321     // success
322
else {
323       iter.dispose();
324       return distance;
325     }
326   }
327
328 // /**
329
// * This is no longer used internally -- highlight is always started on left.
330
// */
331
// public boolean openBraceImmediatelyRight() {
332
// if (_cursor.atEnd()) {
333
// return false;
334
// }
335
// else {
336
// return ((_cursor.getBlockOffset() == 0) && _cursor.current().isOpen() &&
337
// _isCurrentBraceMatchable());
338
// }
339
// }
340

341   public boolean openBraceImmediatelyLeft() {
342     if (_cursor.atStart() || _cursor.atFirstItem()) {
343       return false;
344     }
345     else {
346       _cursor.prev();
347       /*
348       System.out.println("+ closedBraceImmediatelyLeft() {");
349       System.out.println(" _cursor.getBlockOffset(): "+_cursor.getBlockOffset());
350       System.out.println(" _cursor.current().isClosed(): "+_cursor.current().isClosed());
351       System.out.println(" _isCurrentBraceMatchable(): "+_isCurrentBraceMatchable());
352       System.out.println(" }");
353       */

354       boolean isLeft = ((_cursor.getBlockOffset() == 0) && _cursor.current().isOpen() &&
355                         _isCurrentBraceMatchable());
356       //System.out.println("= token to left: " + _cursor);
357
_cursor.next();
358       //String output = (_cursor.atEnd()) ? "<end>": _cursor.toString();
359
//System.out.println("= current token: " + output);
360
return isLeft;
361     }
362   }
363
364   public boolean closedBraceImmediatelyLeft() {
365     if (_cursor.atStart() || _cursor.atFirstItem()) {
366       return false;
367     }
368     else {
369       _cursor.prev();
370       /*
371       System.out.println("+ closedBraceImmediatelyLeft() {");
372       System.out.println(" _cursor.getBlockOffset(): "+_cursor.getBlockOffset());
373       System.out.println(" _cursor.current().isClosed(): "+_cursor.current().isClosed());
374       System.out.println(" _isCurrentBraceMatchable(): "+_isCurrentBraceMatchable());
375       System.out.println(" }");
376       */

377       boolean isLeft = ((_cursor.getBlockOffset() == 0) && _cursor.current().isClosed() &&
378                         _isCurrentBraceMatchable());
379       //System.out.println("= token to left: " + _cursor);
380
_cursor.next();
381       //String output = (_cursor.atEnd()) ? "<end>": _cursor.toString();
382
//System.out.println("= current token: " + output);
383
return isLeft;
384     }
385   }
386
387   /*
388    * If the previous ReducedToken is a closed significant brace,
389    * offset is 0 (i.e., if we're immediately right of said brace),
390    * push the previous Brace onto a Stack and iterate backwards,
391    * keeping track of the distance covered.
392    * - For every open significant Brace, if it matches the top of the Stack,
393    * pop the Stack. Increase the distance by the size of the Brace.
394    * If the Stack is Empty, we have a balance. Return distance.
395    * If the open Brace does not match the top of the Stack, return -1;
396    * We have an unmatched closed Brace at the top of the Stack.
397    * - For every closed significant Brace, push onto the Stack.
398    * Increase distance by size of the Brace, continue.
399    * - Anything else, increase distance by size of the ReducedToken, continue.
400    */

401   public int balanceBackward() {
402     //System.out.println("-------------------------------------------");
403
Stack JavaDoc<ReducedToken> braceStack = new Stack JavaDoc<ReducedToken>();
404     TokenList.Iterator iter = _cursor._copy();
405     resetWalkerLocationToCursor();
406     int relDistance;
407     int distance = 0;
408     if (iter.atStart() || iter.atFirstItem() || !closedBraceImmediatelyLeft()) {
409       //System.out.println("closedBraceImmediatelyLeft(): "+closedBraceImmediatelyLeft());
410
iter.dispose();
411       //System.out.println("! atStart, atFirstItem, or no closed brace");
412
return -1;
413     }
414
415     iter.prev();
416     relDistance = iter.current().getSize();
417     // here we check to make sure there is an open significant brace
418
// immediately to the right of the cursor
419
if (iter.current().isClosedBrace()) {
420       if (moveWalkerGetState(-relDistance) == FREE) {
421         // initialize the distance and the stack with the first brace,
422
// the one we are balancing
423

424         braceStack.push(iter.current());
425         distance += iter.current().getSize();
426         iter.prev();
427         if (!iter.atStart()) {
428           distance += iter.current().getSize();
429           relDistance = iter.current().getSize();
430         }
431       }
432       else {
433         iter.dispose();
434         //System.out.println("! state at relative location != FREE");
435
return -1;
436       }
437     }
438     else {
439       iter.dispose();
440       //System.out.println("! no open brace to immediate right of cursor");
441
return -1;
442     }
443     // either we get a match and the stack is empty
444
// or we reach the start of a file and haven't found a match
445
// or we have a open brace that doesn't have a match,
446
// so we abort
447
while (!iter.atStart() && !braceStack.isEmpty()) {
448       if (!iter.current().isGap()) {
449         if (moveWalkerGetState(-relDistance) ==
450             FREE) {
451               // open
452
if (iter.current().isOpenBrace()) {
453                 ReducedToken popped = braceStack.pop();
454                 if (!iter.current().isMatch(popped)) {
455                   iter.dispose();
456                   //System.out.println("! encountered open brace that didn't match");
457
return -1;
458                 }
459               }
460               // closed
461
else {
462                 braceStack.push(iter.current());
463               }
464             }
465         relDistance = 0;
466       }
467       // no matter what, we always want to increase the distance
468
// by the size of the token we have just gone over
469
iter.prev();
470       if (!iter.atStart() && !braceStack.isEmpty()) {
471         distance += iter.current().getSize();
472         relDistance += iter.current().getSize();
473       }
474     }
475
476     // we couldn't find a match
477
if (!braceStack.isEmpty()) {
478       iter.dispose();
479       //System.out.println("! ran to end of brace stack");
480
return -1;
481     }
482     // success
483
else {
484       iter.dispose();
485       return distance;
486     }
487   }
488
489   protected ReducedModelState moveWalkerGetState(int relDistance) {
490     return _parent.moveWalkerGetState(relDistance);
491   }
492
493   protected void resetWalkerLocationToCursor() {
494     _parent.resetLocation();
495   }
496
497   /** Finds distance to enclosing brace on a preceding line. The field braceInfo.distToNewline holds the distance to
498     * the previous newline. To find the enclosing brace one must first move past this newline. The distance held in
499     * this variable is only to the space in front of the newline hence you must move back that distance + 1.
500     */

501   protected void getDistToEnclosingBrace(IndentInfo braceInfo) {
502     Stack JavaDoc<ReducedToken> braceStack = new Stack JavaDoc<ReducedToken>();
503     TokenList.Iterator iter = _cursor._copy();
504     resetWalkerLocationToCursor();
505     // this is the distance to in front of the previous newline.
506
int relDistance = braceInfo.distToNewline + 1;
507     int distance = relDistance;
508
509     if (braceInfo.distToNewline == -1) {
510       iter.dispose();
511       return;
512     }
513     // move to the proper location, then add the rest of the block and go to the previous.
514
iter.move(-braceInfo.distToNewline - 1);
515     relDistance += iter.getBlockOffset();
516     distance += iter.getBlockOffset();
517
518     //reset the value of braceInfo signiling the necessary newline has
519
//not been found.
520
braceInfo.distToNewline = -1;
521
522     if (iter.atStart() || iter.atFirstItem()) {
523       iter.dispose();
524       return;
525     }
526
527     iter.prev();
528
529     // either we get a match and the stack is empty
530
// or we reach the start of a file and haven't found a match
531
// or we have a open brace that doesn't have a match,
532
// so we abort
533
while (!iter.atStart()) {
534
535       distance += iter.current().getSize();
536       relDistance += iter.current().getSize();
537
538       if (!iter.current().isGap()) {
539
540         if (moveWalkerGetState(-relDistance) == FREE) {
541               // open
542
if (iter.current().isOpenBrace()) {
543                 if (braceStack.isEmpty()) {
544                   braceInfo.braceType = iter.current().getType();
545                   braceInfo.distToBrace = distance;
546                   iter.dispose();
547                   return;
548                 }
549                 ReducedToken popped = braceStack.pop();
550                 if (!iter.current().isMatch(popped)) {
551                   iter.dispose();
552                   return;
553                 }
554               }
555               // closed
556
else {
557                 braceStack.push(iter.current());
558               }
559             }
560         relDistance = 0;
561       }
562       // no matter what, we always want to increase the distance
563
// by the size of the token we have just gone over
564
iter.prev();
565     }
566
567     iter.dispose();
568     return;
569   }
570
571
572   /**
573    * Find the enclosing brace enclosing our current location.
574    */

575   protected void getDistToEnclosingBraceCurrent(IndentInfo braceInfo) {
576     Stack JavaDoc<ReducedToken> braceStack = new Stack JavaDoc<ReducedToken>();
577     TokenList.Iterator iter = _cursor._copy();
578     resetWalkerLocationToCursor();
579     int relDistance = 0;
580     int distance = relDistance;
581
582
583     //move to the proper location, then add the rest of the block
584
// and go to the previous.
585

586     relDistance += iter.getBlockOffset();
587     distance += iter.getBlockOffset();
588
589     //reset the value of braceInfo signiling the necessary newline has
590
//not been found.
591
braceInfo.distToNewlineCurrent = -1;
592
593     if (iter.atStart() || iter.atFirstItem()) {
594       iter.dispose();
595       return;
596     }
597
598     iter.prev();
599
600     // either we get a match and the stack is empty
601
// or we reach the start of a file and haven't found a match
602
// or we have a open brace that doesn't have a match,
603
// so we abort
604
while (!iter.atStart()) {
605
606       distance += iter.current().getSize();
607       relDistance += iter.current().getSize();
608
609       if (!iter.current().isGap()) {
610
611         if (moveWalkerGetState(-relDistance) == FREE) {
612               // open
613
if (iter.current().isOpenBrace()) {
614                 if (braceStack.isEmpty()) {
615     braceInfo.braceTypeCurrent = iter.current().getType();
616                   braceInfo.distToBraceCurrent = distance;
617                   iter.dispose();
618                   return;
619                 }
620                 ReducedToken popped = braceStack.pop();
621                 if (!iter.current().isMatch(popped)) {
622                   iter.dispose();
623                   return;
624                 }
625               }
626               // closed
627
else {
628                 braceStack.push(iter.current());
629               }
630             }
631         relDistance = 0;
632       }
633       // no matter what, we always want to increase the distance
634
// by the size of the token we have just gone over
635
iter.prev();
636     }
637
638     iter.dispose();
639     return;
640   }
641 }
642
Popular Tags