KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > ext > ExtFormatSupport


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.editor.ext;
21
22 import org.netbeans.editor.Syntax;
23 import org.netbeans.editor.TokenID;
24 import org.netbeans.editor.TokenItem;
25 import org.netbeans.editor.ImageTokenID;
26 import org.netbeans.editor.TokenContextPath;
27
28 /**
29 * Extended format-support offers comment-token support,
30 * token-and-text operations and other support.
31 *
32 * @author Miloslav Metelka
33 * @version 1.00
34 */

35
36 public class ExtFormatSupport extends FormatSupport {
37
38     public ExtFormatSupport(FormatWriter formatWriter) {
39         super(formatWriter);
40     }
41
42     /** Find how many EOLs is between two token-position.
43      * @param fromPosition the position from which to start counting.
44      * If it's EOL, it's counted.
45      * @param toPosition the ending position. If it points at EOL,
46      * it's ignored from the total count.
47      * It is necessary for the second position to follow
48      * the first one.
49      */

50     public int findLineDistance(FormatTokenPosition fromPosition,
51     FormatTokenPosition toPosition) {
52         int lineCounter = 0;
53
54         TokenItem token = fromPosition.getToken();
55         int offset = fromPosition.getOffset();
56         TokenItem targetToken = toPosition.getToken();
57         int targetOffset = toPosition.getOffset();
58
59         // Solve special case if both positions are ending
60
if (token == null && targetToken == null) {
61             return 0;
62         }
63
64         while (token != null) {
65             String JavaDoc text = token.getImage();
66             int textLen = text.length();
67             while (offset < textLen) {
68                 if (token == targetToken && offset == targetOffset) {
69                     return lineCounter;
70                 }
71
72                 if (text.charAt(offset) == '\n') {
73                     lineCounter++;
74                 }
75
76                 offset++;
77             }
78
79             token = token.getNext();
80             offset = 0;
81         }
82
83         throw new IllegalStateException JavaDoc("Tokens don't follow in chain."); // NOI18N
84
}
85
86     /** Is the given token a comment token? By default it returns
87     * false but it can be redefined in descendants.
88     */

89     public boolean isComment(TokenItem token, int offset) {
90         return false;
91     }
92
93     public boolean isComment(FormatTokenPosition pos) {
94         return isComment(pos.getToken(), pos.getOffset());
95     }
96
97     /** Whether the given position is not a whitespace or comment. */
98     public boolean isImportant(TokenItem token, int offset) {
99         return !isComment(token, offset) && !isWhitespace(token, offset);
100     }
101
102     public boolean isImportant(FormatTokenPosition pos) {
103         return isImportant(pos.getToken(), pos.getOffset());
104     }
105
106     /** Get the first position that is not whitespace and that is not comment.
107     * @param startPosition position from which the search starts.
108     * For the backward search the character right at startPosition
109     * is not considered as part of the search.
110     * @param limitPosition position where the search will be broken
111     * reporting that nothing was found. It can be null to search
112     * till the end or begining of the chain (depending on direction).
113     * @param stopOnEOL whether stop and return EOL token or continue search if
114     * EOL token is found.
115     * @param backward whether search in backward direction.
116     * @return first non-whitespace token or EOL or null if all the tokens
117     * till the begining of the chain are whitespaces.
118     */

119     public FormatTokenPosition findImportant(FormatTokenPosition startPosition,
120     FormatTokenPosition limitPosition, boolean stopOnEOL, boolean backward) {
121         // Return immediately for equal positions
122
if (startPosition.equals(limitPosition)) {
123             return null;
124         }
125
126         if (backward) {
127             TokenItem limitToken;
128             int limitOffset;
129
130             if (limitPosition == null) {
131                 limitToken = null;
132                 limitOffset = 0;
133
134             } else { // valid limit position
135
limitPosition = getPreviousPosition(limitPosition);
136                 if (limitPosition == null) {
137                     limitToken = null;
138                     limitOffset = 0;
139
140                 } else { // valid limit position
141
limitToken = limitPosition.getToken();
142                     limitOffset = limitPosition.getOffset();
143                 }
144             }
145
146             startPosition = getPreviousPosition(startPosition);
147             if (startPosition == null) {
148                 return null;
149             }
150
151             TokenItem token = startPosition.getToken();
152             int offset = startPosition.getOffset();
153
154             while (true) {
155                 String JavaDoc text = token.getImage();
156                 while (offset >= 0) {
157                     if (stopOnEOL && text.charAt(offset) == '\n') {
158                         return null;
159                     }
160
161                     if (isImportant(token, offset)) {
162                         return getPosition(token, offset);
163                     }
164
165                     if (token == limitToken && offset == limitOffset) {
166                         return null;
167                     }
168
169                     offset--;
170                 }
171
172                 token = token.getPrevious();
173                 if (token == null) {
174                     return null;
175                 }
176                 offset = token.getImage().length() - 1;
177             }
178
179         } else { // forward direction
180
TokenItem limitToken;
181             int limitOffset;
182
183             if (limitPosition == null) {
184                 limitToken = null;
185                 limitOffset = 0;
186
187             } else { // valid limit position
188
limitToken = limitPosition.getToken();
189                 limitOffset = limitPosition.getOffset();
190             }
191
192             TokenItem token = startPosition.getToken();
193             int offset = startPosition.getOffset();
194
195             if (token == null)
196                 return null;
197             
198             while (true) {
199                 String JavaDoc text = token.getImage();
200                 int textLen = text.length();
201                 while (offset < textLen) {
202                     if (token == limitToken && offset == limitOffset) {
203                         return null;
204                     }
205
206                     if (stopOnEOL && text.charAt(offset) == '\n') {
207                         return null;
208                     }
209
210                     if (isImportant(token, offset)) {
211                         return getPosition(token, offset);
212                     }
213
214                     offset++;
215                 }
216
217                 token = token.getNext();
218                 if (token == null) {
219                     return null;
220                 }
221                 offset = 0;
222             }
223         }
224     }
225
226     /** Get the first non-whitespace and non-comment token or null.
227      * @param pos any position on the line.
228      */

229     public FormatTokenPosition findLineFirstImportant(FormatTokenPosition pos) {
230         pos = findLineStart(pos);
231         TokenItem token = pos.getToken();
232         int offset = pos.getOffset();
233
234         if (token == null) { // no line start, no WS
235
return null;
236         }
237
238         while (true) {
239             String JavaDoc text = token.getImage();
240             int textLen = text.length();
241             while (offset < textLen) {
242                 if (text.charAt(offset) == '\n') {
243                     return null;
244                 }
245
246                 if (isImportant(token, offset)) {
247                     return getPosition(token, offset);
248                 }
249
250                 offset++;
251             }
252
253             if (token.getNext() == null) {
254                 return null;
255             }
256
257             token = token.getNext();
258             offset = 0;
259         }
260     }
261
262     /** Get the start of the area of line where there is only
263      * whitespace or comment till the end of the line.
264      * @param pos any position on the line.
265      * Return null if there's no such area.
266      */

267     public FormatTokenPosition findLineEndNonImportant(FormatTokenPosition pos) {
268         pos = findLineEnd(pos);
269         if (isChainStartPosition(pos)) { // empty first line
270
return pos;
271
272         } else {
273             pos = getPreviousPosition(pos);
274         }
275
276
277         TokenItem token = pos.getToken();
278         int offset = pos.getOffset();
279
280         while (true) {
281             String JavaDoc text = token.getImage();
282             int textLen = text.length();
283             while (offset >= 0) {
284                 if (offset < textLen
285                     && ((text.charAt(offset) == '\n')
286                         || isImportant(token, offset))
287                         
288                 ) {
289                     return getNextPosition(token, offset);
290                 }
291
292
293                 offset--;
294             }
295
296             if (token.getPrevious() == null) {
297                 // This is the first token in chain, return position 0
298
return getPosition(token, 0);
299             }
300
301             token = token.getPrevious();
302             offset = token.getImage().length() - 1;
303         }
304     }
305
306     /** Insert the token that has token-id containing image, so additional
307     * text is not necessary.
308     */

309     public TokenItem insertImageToken(TokenItem beforeToken,
310     ImageTokenID tokenID, TokenContextPath tokenContextPath) {
311         return super.insertToken(beforeToken, tokenID, tokenContextPath,
312                 tokenID.getImage());
313     }
314
315     /** Find the token either by token-id or token-text or both.
316     * @param startToken token from which to start searching. For backward
317     * search this token is excluded from the search.
318     * @param limitToken the token where the search will be broken
319     * reporting that nothing was found. It can be null to search
320     * till the end or begining of the chain (depending on direction).
321     * For forward search this token is not considered to be part of search,
322     * but for backward search it is.
323     * @param tokenID token-id to be searched. If null the token-id
324     * of the tokens inspected will be ignored.
325     * @param tokenImage text of the token to find. If null the text
326     * of the tokens inspected will be ignored.
327     * @param backward true for searching in backward direction or false
328     * to serach in forward direction.
329     * @return return the matching token or null if nothing was found
330     */

331     public TokenItem findToken(TokenItem startToken, TokenItem limitToken,
332     TokenID tokenID, TokenContextPath tokenContextPath,
333     String JavaDoc tokenImage, boolean backward) {
334
335         if (backward) { // go to the previous token for the backward search
336
if (startToken != null && startToken == limitToken) { // empty search
337
return null;
338             }
339
340             startToken = getPreviousToken(startToken);
341
342             if (limitToken != null) {
343                 limitToken = limitToken.getPrevious();
344             }
345         }
346
347         while (startToken != null && startToken != limitToken) {
348             if (tokenEquals(startToken, tokenID, tokenContextPath, tokenImage)) {
349                 return startToken;
350             }
351
352             startToken = backward ? startToken.getPrevious() : startToken.getNext();
353         }
354
355         return null;
356     }
357
358     /** Find the first non-whitespace and non-comment token in the given
359      * direction. This is similair to <tt>findImportant()</tt>
360      * but it operates over the tokens.
361      * @param startToken token from which to start searching. For backward
362      * search this token is excluded from the search.
363      * @param limitToken the token where the search will be broken
364      * reporting that nothing was found. It can be null to search
365      * till the end or begining of the chain (depending on direction).
366      * For forward search this token is not considered to be part of search,
367      * but for backward search it is.
368      * @param backward true for searching in backward direction or false
369      * to serach in forward direction.
370      * @return return the matching token or null if nothing was found
371      */

372     public TokenItem findImportantToken(TokenItem startToken, TokenItem limitToken,
373     boolean backward) {
374
375         if (backward) { // go to the previous token for the backward search
376
if (startToken != null && startToken == limitToken) { // empty search
377
return null;
378             }
379
380             startToken = getPreviousToken(startToken);
381
382             if (limitToken != null) {
383                 limitToken = limitToken.getPrevious();
384             }
385         }
386
387         while (startToken != null && startToken != limitToken) {
388             if (isImportant(startToken, 0)) {
389                 return startToken;
390             }
391
392             startToken = backward ? startToken.getPrevious() : startToken.getNext();
393         }
394
395         return null;
396     }
397
398     /** This method can be used to find a matching brace token. Both
399     * the token-id and token-text are used for comparison of the starting token.
400     * @param startToken token from which to start. It cannot be null.
401     * For backward search this token is ignored and the previous one is used.
402     * @param limitToken the token where the search will be broken
403     * reporting that nothing was found. It can be null to search
404     * till the end or begining of the chain (depending on direction).
405     * For forward search this token is not considered to be part of search,
406     * but for backward search it is.
407     * @param matchTokenID matching token-id for the start token.
408     * @param matchTokenImage matching token-text for the start token.
409     * @param backward true for searching in backward direction or false
410     * to serach in forward direction.
411     */

412     public TokenItem findMatchingToken(TokenItem startToken, TokenItem limitToken,
413     TokenID matchTokenID, String JavaDoc matchTokenImage, boolean backward) {
414
415         int depth = 0;
416         TokenID startTokenID = startToken.getTokenID();
417         TokenContextPath startTokenContextPath = startToken.getTokenContextPath();
418         String JavaDoc startText = startToken.getImage();
419
420         // Start to search from the adjacent item
421
TokenItem token = backward ? startToken.getPrevious() : startToken.getNext();
422
423         while (token != null && token != limitToken) {
424             if (tokenEquals(token, matchTokenID, startTokenContextPath,
425                 matchTokenImage)
426             ) {
427                 if (depth-- == 0) {
428                     return token;
429                 }
430
431             } else if (tokenEquals(token, startTokenID, startTokenContextPath,
432                 startText)
433             ) {
434                 depth++;
435             }
436
437             token = backward ? token.getPrevious() : token.getNext();
438         }
439
440         return null;
441     }
442
443     public TokenItem findMatchingToken(TokenItem startToken, TokenItem limitToken,
444     ImageTokenID matchTokenID, boolean backward) {
445         return findMatchingToken(startToken, limitToken, matchTokenID,
446             matchTokenID.getImage(), backward);
447     }
448         
449     /** Search for any of the image tokens from the given array
450     * and return if the token matches any item from the array.
451     * The index of the item from the array that matched
452     * can be found by calling <tt>getIndex()</tt> method.
453     * It is suitable mainly for the image-token-ids.
454     *
455     * @param startToken token from which to start. For backward search
456     * this token is excluded from the search.
457     * @param limitToken the token where the search will be broken
458     * reporting that nothing was found. It can be null to search
459     * till the end or begining of the chain (depending on direction).
460     * For forward search this token is not considered to be part of search,
461     * but for backward search it is.
462     * @param tokenIDArray array of the token-ids for which to search.
463     * @param tokenContextPath context path that the found token must have.
464     * It can be null.
465     * @param backward true for searching in backward direction or false
466     * to serach in forward direction.
467     */

468     public TokenItem findAnyToken(TokenItem startToken, TokenItem limitToken,
469     TokenID[] tokenIDArray, TokenContextPath tokenContextPath, boolean backward) {
470
471         if (backward) { // go to the previous token for the backward search
472
if (startToken != null && startToken == limitToken) { // empty search
473
return null;
474             }
475
476             startToken = getPreviousToken(startToken);
477
478             if (limitToken != null) {
479                 limitToken = limitToken.getPrevious();
480             }
481         }
482
483         while (startToken != null && startToken != limitToken) {
484             for (int i = 0; i < tokenIDArray.length; i++) {
485                 if (tokenEquals(startToken, tokenIDArray[i], tokenContextPath)) {
486                     return startToken;
487                 }
488             }
489
490             startToken = backward ? startToken.getPrevious() : startToken.getNext();
491         }
492
493         return null;
494     }
495
496     /** Get the index of the token in the given token-id-and-text array or -1
497     * if the token is not in the array.
498     */

499     public int getIndex(TokenItem token, TokenID[] tokenIDArray) {
500         for (int i = 0; i < tokenIDArray.length; i++) {
501             if (tokenEquals(token, tokenIDArray[i])) {
502                 return i;
503             }
504         }
505         return -1; // not found
506
}
507
508     /** Remove the ending whitespace from the line.
509      * @param pos position on the line to be checked.
510      * @return position of the EOL on the line or end of chain position
511      */

512     public FormatTokenPosition removeLineEndWhitespace(FormatTokenPosition pos) {
513         FormatTokenPosition endWS = findLineEndWhitespace(pos);
514         if (endWS == null || endWS.getToken() == null) { // no WS on line
515
return findLineEnd(pos);
516
517         } else { // some WS on line
518
int removeInd;
519             TokenItem token = endWS.getToken();
520             int offset = endWS.getOffset();
521
522             while (true) {
523                 String JavaDoc text = token.getImage();
524                 int textLen = text.length();
525                 removeInd = offset;
526                 while (offset < textLen) {
527                     if (text.charAt(offset) == '\n') {
528                         remove(token, removeInd, offset - removeInd);
529                         return getPosition(token, removeInd);
530                     }
531
532                     offset++;
533                 }
534
535                 TokenItem nextToken = token.getNext();
536                 if (removeInd == 0) {
537                     removeToken(token);
538
539                 } else { // only ending part removed
540
remove(token, removeInd, textLen - removeInd);
541                 }
542
543                 token = nextToken;
544                 if (token == null) {
545                     return getPosition(null, 0);
546                 }
547                 offset = 0;
548             }
549         }
550     }
551
552     /** Get the character at the given position. The caller must care
553      * about not to pass the end-of-chain position to this method.
554      */

555     public char getChar(FormatTokenPosition pos) {
556         return pos.getToken().getImage().charAt(pos.getOffset());
557     }
558
559     /** Whether the given position is at the begining of the line. */
560     public boolean isLineStart(FormatTokenPosition pos) {
561         return isChainStartPosition(pos) || getChar(getPreviousPosition(pos)) == '\n';
562     }
563
564     public boolean isNewLine(FormatTokenPosition pos) {
565         return (pos.getToken() != null) && getChar(pos) == '\n';
566     }
567
568 }
569
Popular Tags