KickJava   Java API By Example, From Geeks To Geeks.

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


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 /** Keeps track of newlines, comment blocks, and single and double-quoted strings. This reduced sub-model is used for
37  * coloring purposes. Given the information contained here, the DefinitionsEditorKit can paint strings, comments, and
38  * regular code in different colors. DefinitionsEditorKit colors keywords by directly reading DefinitionsDocument,
39  * the "full-scale" model.
40  * @version $Id: ReducedModelComment.java 4043 2006-11-22 23:04:59Z rcartwright $
41  */

42
43 public class ReducedModelComment extends AbstractReducedModel {
44
45   /** Can be used by other classes to walk through the list of comment chars*/
46   TokenList.Iterator _walker;
47
48   /** Constructor. Creates a new reduced model with the cursor at the start of a blank "page." */
49   public ReducedModelComment() {
50     super();
51     _walker = _cursor._copy();
52   }
53
54   public void insertChar(char ch) {
55     switch(ch) {
56       case '*': insertSpecial("*"); break;
57       case '/': insertSpecial("/"); break;
58       case '\n': insertNewline(); break;
59       case '\\': insertSpecial("\\"); break;
60       case '\'': insertQuote("'"); break;
61       case '\"': insertQuote("\""); break;
62       default:
63         _insertGap(1); break;
64     }
65   }
66
67   /**
68   * Inserts one of three special chars, (*),(/), or (\).
69   * <OL>
70   * <li> empty list: insert slash
71   * <li> atEnd: check previous and insert slash
72   * <li> inside multiple character brace:
73   * <ol>
74   * <li> break current brace
75   * <li> move next to make second part current
76   * <li> insert brace between broken parts of former brace
77   * <li> move previous twice to get before the broken first part
78   * <li> walk
79   * <li> current = multiple char brace? move next once<BR>
80   * current = single char brace? move next twice<BR>
81   * We moved two previous, but if the broken part combined with
82   * the insert, there's only one brace where once were two.
83   * </ol>
84   * <li> inside a gap: use helper function
85   * <li> before a multiple char brace:
86   * <ol>
87   * <li> break the current brace
88   * <li> check previous and insert
89   * </ol>
90   * <li>otherwise, check previous and insert
91   * </OL>
92   */

93   private void insertSpecial(String JavaDoc special) {
94     // Check if empty.
95
if (_tokens.isEmpty()) {
96       _cursor.insertNewBrace(special); //now pointing to tail.
97
return;
98     }
99     // Check if at start.
100
if (_cursor.atStart()) _cursor.next();
101     
102     // Not empty, not at start, if at end check the previous brace
103
if (_cursor.atEnd()) _checkPreviousInsertSpecial(special);
104     
105     // If inside a double character brace, break it.
106
else if (_cursor.getBlockOffset() > 0 && _cursor.current().isMultipleCharBrace()) {
107       _cursor._splitCurrentIfCommentBlock(true,true);
108       //leaving us at the start
109
_cursor.next(); //leaving us after first char
110
_cursor.insertNewBrace(special); //leaves us after the insert
111
move(-2);
112       _updateBasedOnCurrentState();
113       move(2);
114     }
115     // inside a gap
116
else if (_cursor.getBlockOffset() > 0 && _cursor.current().isGap()) {
117       _cursor.insertBraceToGap(special);
118       _cursor.prev();
119       _cursor.prev();
120       _updateBasedOnCurrentState();
121       // restore cursor state
122
_cursor.next();
123       _cursor.next();
124       // update based on current state
125
}
126     //if at start of double character brace, break it.
127
else if ((_cursor.getBlockOffset() == 0) && _cursor.current().isMultipleCharBrace()) {
128       //if we're free there won't be a block comment close so if there
129
//is then we don't want to break it. If the special character is
130
// a backslash, we want to break the following escape sequence if there
131
// is one.
132
_cursor._splitCurrentIfCommentBlock(false,special.equals("\\"));
133       //leaving us at start
134

135       _checkPreviousInsertSpecial(special);
136     }
137     else _checkPreviousInsertSpecial(special);
138   }
139
140   /**
141    * Checks before point of insertion to make sure we don't need to combine.
142    * Delegates work to _checkPreviousInsertBackSlash and _checkPreviousInsertCommentChar,
143    * depending on what's being inserted into the document.
144    */

145   private void _checkPreviousInsertSpecial(String JavaDoc special) {
146     if (special.equals("\\")) {
147       _checkPreviousInsertBackSlash();
148     }
149     else {
150       _checkPreviousInsertCommentChar(special);
151     }
152   }
153
154   /** Checks before point of insertion to make sure we don't need to combine
155    * backslash with another backslash (yes, they too can be escaped).
156    */

157
158   private void _checkPreviousInsertBackSlash() {
159     if (!_cursor.atStart() && !_cursor.atFirstItem()) {
160       if (_cursor.prevItem().getType().equals("\\")) {
161         _cursor.prevItem().setType("\\\\");
162         _updateBasedOnCurrentState();
163         return;
164       }
165     }
166     // Here we know the / unites with nothing behind it.
167
_cursor.insertNewBrace("\\"); //leaving us after the brace.
168
_cursor.prev();
169     _updateBasedOnCurrentState();
170     if (_cursor.current().getSize() == 2) _cursor.setBlockOffset(1);
171     else _cursor.next();
172   }
173
174   /** Checks before the place of insert to make sure there are no preceding
175    * slashes with which the inserted slash must combine. It then performs
176    * the insert of either (/), (/ /), (/ *) or (* /).
177    */

178   private void _checkPreviousInsertCommentChar(String JavaDoc special) {
179     if (!_cursor.atStart() && !_cursor.atFirstItem()) {
180       if ((_cursor.prevItem().getType().equals("/")) && (_cursor.prevItem().getState() == FREE)) {
181             _cursor.prevItem().setType("/" + special);
182             _updateBasedOnCurrentState();
183             return;
184           }
185       // if we're after a star,
186
else if (_cursor.prevItem().getType().equals("*") &&
187                getStateAtCurrent() == INSIDE_BLOCK_COMMENT &&
188                special.equals("/")) {
189           _cursor.prevItem().setType("*" + special);
190           _cursor.prevItem().setState(FREE);
191           _updateBasedOnCurrentState();
192           return;
193         }
194     }
195     //Here we know the / unites with nothing behind it.
196
_cursor.insertNewBrace(special); //leaving us after the brace.
197
_cursor.prev();
198     _updateBasedOnCurrentState();
199     if (_cursor.current().getSize() == 2) _cursor.setBlockOffset(1);
200     else _cursor.next();
201   }
202
203   /**
204   * Inserts an end-of-line character.
205   * <OL>
206   * <li> atStart: insert
207   * <li> atEnd: insert
208   * <li> inside multiple character brace:
209   * <ol>
210   * <li> break current brace
211   * <li> move next to make second part current
212   * <li> insert brace between broken parts of former brace
213   * <li> move previous twice to get before the broken first part
214   * <li> walk
215   * <li> move next twice to be after newline insertion
216   * </ol>
217   * <li> inside a gap: use helper function
218   * <li>otherwise, just insert normally
219   * </OL>
220   */

221   public void insertNewline() {
222     if (_cursor.atStart()) {
223       _insertNewEndOfLine();
224     }
225     else if (_cursor.atEnd()) {
226       _insertNewEndOfLine();
227     }
228     else if ((_cursor.getBlockOffset() > 0) && _cursor.current().isMultipleCharBrace()) {
229       _cursor._splitCurrentIfCommentBlock(true, true);
230       _cursor.next();
231       _cursor.insert(Brace.MakeBrace("\n", getStateAtCurrent()));
232       _cursor.prev();
233       _updateBasedOnCurrentState();
234       _cursor.next();
235       _cursor.next();
236       _cursor.setBlockOffset(0);
237     }
238     else if ((_cursor.getBlockOffset() > 0) && _cursor.current().isGap()) {
239       _cursor.insertBraceToGap("\n");
240       _cursor.prev();
241       _cursor.prev();
242       _updateBasedOnCurrentState();
243       // restore cursor state
244
_cursor.next();
245       _cursor.next();
246     }
247     else {
248       _insertNewEndOfLine();
249     }
250     return;
251   }
252
253   private void _insertNewEndOfLine() {
254     _cursor.insertNewBrace("\n");
255     _cursor.prev();
256     _updateBasedOnCurrentState();
257     _cursor.next();
258     _cursor.setBlockOffset(0);
259   }
260
261   /**
262    * Inserts the specified quote character.
263    * <OL>
264    * <li> atStart: insert
265    * <li> atEnd: insert
266    * <li> inside multiple character brace:
267    * <ol>
268    * <li> break current brace
269    * <li> move next to make second part current
270    * <li> insert brace between broken parts of former brace
271    * <li> walk
272    * <li> current = multiple char brace? move next once<BR>
273    * current = single char brace? move next twice<BR>
274    * We moved two previous, but if the broken part combined with
275    * the insert, there's only one brace where once were two.
276    * <li> move next twice to be after newline insertion
277    * </ol>
278    * <li> inside a gap: use helper function
279    * <li> before a multiple char brace:
280    * <ol>
281    * <li> break the current brace
282    * <li> check previous and insert
283    * </ol>
284    * <li>otherwise, just insert normally
285    * </OL>
286    * @param quote the type of quote to insert
287    */

288   public void insertQuote(String JavaDoc quote) {
289     if (_cursor.atStart()) {
290       _insertNewQuote(quote);
291     }
292     else if (_cursor.atEnd()) {
293       _insertNewQuote(quote);
294     }
295     // in the middle of a multiple character brace
296
else if ((_cursor.getBlockOffset() > 0) && _cursor.current().isMultipleCharBrace()) {
297       _cursor._splitCurrentIfCommentBlock(true,true);
298       _cursor.next();
299       _cursor.insert(Brace.MakeBrace(quote, getStateAtCurrent()));
300       _cursor.prev();
301       _updateBasedOnCurrentState();
302       if (!_cursor.current().isMultipleCharBrace())
303         _cursor.next();
304       _cursor.next();
305       _cursor.setBlockOffset(0);
306     }
307     // in the middle of a gap
308
else if ((_cursor.getBlockOffset() > 0) && _cursor.current().isGap()) {
309       _cursor.insertBraceToGap(quote);
310       _cursor.prev();
311       _cursor.prev();
312       _updateBasedOnCurrentState();
313       // restore cursor state
314
_cursor.next();
315       _cursor.next();
316
317     }
318     else _insertNewQuote(quote);
319     return;
320   }
321
322   /**
323    * Helper function for insertQuote. Creates a new quote Brace and puts it in the
324    * reduced model.
325    * @param quote the quote to insert
326    */

327   private void _insertNewQuote(String JavaDoc quote) {
328     String JavaDoc insert = _getQuoteType(quote);
329     _cursor.insertNewBrace(insert);
330     _cursor.prev();
331     _updateBasedOnCurrentState();
332     _cursor.next();
333     _cursor.setBlockOffset(0);
334   }
335
336   /**
337    * Helper function for insertNewQuote. In the case where a backslash
338    * precedes the point of insertion, it removes the backslash and returns
339    * the text for an escaped quote. The type of quote depends on the given
340    * argument.
341    * @param quote the type of quote to insert
342    * @return a regular or escaped quote, depending on what was previous
343    */

344   private String JavaDoc _getQuoteType(String JavaDoc quote) {
345     if (_cursor.atStart() || _cursor.atFirstItem()) return quote;
346     else if (_cursor.prevItem().getType().equals("\\")) {
347       _cursor.prev();
348       _cursor.remove();
349       return "\\" + quote;
350     }
351     else return quote;
352   }
353
354   /** Inserts a gap between the characters in a multiple character brace. This function is called by
355    * AbstractReducedModel's method insertGap when a Gap is inserted between the characters in a comment brace or an
356    * escape sequence. It splits up the multiple character brace into its component parts and inserts a Gap of size
357    * length in between the resulting split parts.
358    * @param length the size of the Gap to be inserted in characters
359    */

360   protected void insertGapBetweenMultiCharBrace(int length) {
361     if (_cursor.getBlockOffset() > 1)
362       throw new IllegalArgumentException JavaDoc("OFFSET TOO BIG: " + _cursor.getBlockOffset());
363     
364     _cursor._splitCurrentIfCommentBlock(true, true);
365     _cursor.next();
366     _insertNewGap(length); //inserts gap and goes to next item
367
// we have to go back two tokens; we don't want to use move because it could
368
// throw us past start if there was only one character before us and we went
369
// the usual 2 spaces before. There would have to be a check and a branch
370
// depending on conditions that way.
371
_cursor.prev();
372     _cursor.prev();
373     _updateBasedOnCurrentState();
374     // restore cursor state
375
_cursor.next();
376     _cursor.next();
377     return;
378   }
379   
380   /** USE RULES:
381    * Inserting between braces: This should be called from between the two
382    * characters of the broken double comment.
383    * Deleting special chars: Start from previous char if it exists.
384    * Begins updating at current character. /./ would not become // because current is in the middle.
385    * Double character comments inside of a quote or a comment are broken.
386    */

387
388   private void _updateBasedOnCurrentState() {
389     TokenList.Iterator copyCursor = _cursor._copy();
390     copyCursor.updateBasedOnCurrentState();
391     copyCursor.dispose();
392   }
393
394  /** Updates the BraceReduction to reflect cursor movement. Negative values move left from the cursor, positive values
395   * move right.
396   * @param count indicates the direction and magnitude of cursor movement
397   */

398   public void move(int count) { _cursor.move(count); }
399
400   /** <P>Update the BraceReduction to reflect text deletion.</P>
401    * @param count indicates the size and direction of text deletion.
402    * Negative values delete text to the left of the cursor, positive values delete text to the right.
403    * Always move count spaces to make sure we can delete.
404    */

405   public void delete(int count) {
406     if (count == 0) return;
407     
408     _cursor.delete(count);
409
410     // Changes in ReducedModelComment can entail state changes in the
411
// document. For this reason, we have to call
412
// _updateBasedOnCurrentState because there is no need to call it
413
// in ReducedModelBrace, and factoring it out would be stupid and
414
// wasteful.
415

416     // Move back 2 or as far back as the document will allow
417
int absOff = this.absOffset();
418     int movement;
419     if (absOff < 2) movement = absOff;
420     else movement = 2;
421     _cursor.move(-movement);
422     // update state information
423
_updateBasedOnCurrentState();
424     // restore the cursor
425
_cursor.move(movement);
426     return;
427   }
428
429
430   /* In order to interface with the ReducedModelComment two functions are
431      provided. One resets the walker and the other will both move the cursor
432      by x and return the state at that new location.
433      Once the new value has returned all new calculations will be relative to
434      that spot until the walker is reset to the _cursor. */

435
436   /** Returns the state at the relLocation, where relLocation is the location relative to the walker
437    * @param relLocation distance from walker to get state at.
438    */

439   protected ReducedModelState moveWalkerGetState(int relLocation) {
440     _walker.move(relLocation);
441     return _walker.getStateAtCurrent();
442   }
443
444   /** Resets the walker to the current position in document */
445   protected void resetWalkerLocationToCursor() {
446     _walker.dispose();
447     _walker = _cursor._copy();
448   }
449
450   /** Dist to Previous newline will be -1 if no newline. */
451   void getDistToPreviousNewline(IndentInfo braceInfo) {
452     braceInfo.distToPrevNewline = _getDistToPreviousNewline(_cursor._copy());
453     braceInfo.distToNewline = braceInfo.distToPrevNewline;
454     return;
455   }
456
457   /** Returns distance to after newline. */
458   private int _getDistToPreviousNewline(TokenList.Iterator copyCursor) {
459     int walkcount = copyCursor.getBlockOffset();
460     if (!copyCursor.atStart()) copyCursor.prev();
461     while ((!copyCursor.atStart()) &&
462            (!(copyCursor.current().getType().equals("\n"))))
463            {
464              // copyCursor.current().getState() == FREE))) {
465
walkcount += copyCursor.current().getSize();
466              copyCursor.prev();
467            }
468
469     if (copyCursor.atStart()) return -1;
470     return walkcount;
471   }
472
473   void getDistToIndentNewline(IndentInfo braceInfo) {
474     TokenList.Iterator copyCursor = _cursor._copy();
475
476     if (braceInfo.distToBrace == -1 || copyCursor.atStart())
477       return; // no brace
478

479     copyCursor.move(-braceInfo.distToBrace);
480     int walkcount = _getDistToPreviousNewline(copyCursor);
481
482     if (walkcount == -1) {
483       braceInfo.distToNewline = -1;
484     }
485     else {
486       braceInfo.distToNewline = walkcount + braceInfo.distToBrace;
487     }
488     return;
489   }
490
491 /**
492  * Computes the distance to the beginning of the line containing the brace enclosing
493  * the current location. Stores this info in the IndentInfo field distToNewlineCurrent.
494  */

495   void getDistToCurrentBraceNewline(IndentInfo braceInfo) {
496     TokenList.Iterator copyCursor = _cursor._copy();
497
498     if (braceInfo.distToBraceCurrent == -1 || copyCursor.atStart()) { // no brace
499
return;
500     }
501
502     copyCursor.move(-braceInfo.distToBraceCurrent);
503     int walkcount = _getDistToPreviousNewline(copyCursor);
504
505     if (walkcount == -1) {
506       braceInfo.distToNewlineCurrent = -1;
507     }
508     else {
509       braceInfo.distToNewlineCurrent = walkcount + braceInfo.distToBraceCurrent;
510     }
511     return;
512   }
513
514   /**
515   * Gets distance to previous newline, relLoc is the distance
516   * back from the cursor that we want to start searching.
517   */

518   public int getDistToPreviousNewline(int relLoc) {
519     TokenList.Iterator copyCursor = _cursor._copy();
520     copyCursor.move(-relLoc);
521     int dist = _getDistToPreviousNewline(copyCursor);
522     copyCursor.dispose();
523     if (dist == -1) {
524       return -1;
525     }
526     return dist + relLoc;
527   }
528
529   /** Returns the distance to the gap before the next newline (end of document if no newline) */
530   public int getDistToNextNewline() {
531     TokenList.Iterator copyCursor = _cursor._copy();
532     if (copyCursor.atStart()) {
533       copyCursor.next();
534     }
535     if (copyCursor.atEnd() || copyCursor.current().getType().equals("\n")) {
536       return 0;
537     }
538     int walkcount = copyCursor.current().getSize() - _cursor.getBlockOffset();
539     copyCursor.next();
540
541     while ((!copyCursor.atEnd()) &&
542            (!(copyCursor.current().getType().equals("\n"))))
543     {
544       //copyCursor.current().getState() == FREE))) {
545
walkcount += copyCursor.current().getSize();
546       copyCursor.next();
547     }
548     return walkcount;
549   }
550 }
551
Popular Tags