KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > FinderFactory


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;
21
22 /**
23 * Various finders are located here.
24 *
25 * @author Miloslav Metelka
26 * @version 1.00
27 */

28
29 public class FinderFactory {
30
31     /** Abstract finder implementation. The only <CODE>find()</CODE>
32     * method must be redefined.
33     */

34     public static abstract class AbstractFinder implements Finder {
35
36         /** Was the string found? */
37         protected boolean found;
38
39         /** Was the string found? */
40         public final boolean isFound() {
41             return found;
42         }
43
44         /** Reset the finder */
45         public void reset() {
46             found = false;
47         }
48
49     }
50
51     /** Return successful match on the first searched char */
52     public static class TrueFinder extends AbstractFinder {
53
54         public int find(int bufferStartPos, char buffer[],
55                         int offset1, int offset2, int reqPos, int limitPos) {
56             found = true;
57             return reqPos;
58         }
59
60     }
61
62     /** Request non-existent position immediately */
63     public static class FalseFinder extends AbstractFinder
64         implements StringFinder {
65
66         public int find(int bufferStartPos, char buffer[],
67                         int offset1, int offset2, int reqPos, int limitPos) {
68             return -1;
69         }
70
71         public int getFoundLength() {
72             return 0;
73         }
74
75     }
76
77     /** Finder for getting visual column value for particular position.
78     * The starting position for find must be the start of particular
79     * line. The limit position should be set to position for which
80     * the visual column is requested. This method can be used only
81     * in case the font is superfixed i.e. all the characters of all
82     * font styles have the same width.
83     */

84     public static final class PosVisColFwdFinder extends AbstractFinder {
85
86         /** Visual column on line */
87         int visCol;
88
89         /** Tab size for particular document scanned */
90         int tabSize;
91
92         /** Get visual column that this finder computed */
93         public int getVisCol() {
94             return visCol;
95         }
96
97         public void setTabSize(int tabSize) {
98             this.tabSize = tabSize;
99         }
100
101         /** Mark that first call will follow */
102         public void reset() {
103             super.reset();
104             visCol = 0;
105         }
106
107         /** finds BOL on current line */
108         public int find(int bufferStartPos, char buffer[],
109                         int offset1, int offset2, int reqPos, int limitPos) {
110
111             int offset = reqPos - bufferStartPos;
112             while (offset < offset2) {
113                 if (buffer[offset] == '\t') {
114                     visCol = (visCol + tabSize) / tabSize * tabSize;
115                 } else {
116                     visCol++;
117                 }
118                 offset++;
119             }
120             return bufferStartPos + offset;
121         }
122
123     }
124
125     /** Finder for getting position from visual column knowledge.
126     * It is kind of reverse finder for <CODE>PosVisColFwdFinder</CODE>.
127     * The starting position for find should be the start of particular
128     * line. The found position will be that position in document
129     * that corresponds to the column position. This method can be used only
130     * in case the font is superfixed i.e. all the characters of all
131     * font styles have the same width.
132     */

133     public static final class VisColPosFwdFinder extends AbstractFinder {
134
135         /** Visual column position on line */
136         int visCol;
137
138         /** Current visual position as tracked by finder */
139         int curVisCol;
140
141         /** Tab size for particular document scanned */
142         int tabSize;
143
144         /** Extended UI to get character widths */
145         EditorUI editorUI;
146
147         /** Set visual column that this finder will try to reach */
148         public void setVisCol(int visCol) {
149             this.visCol = visCol;
150         }
151
152         public void setTabSize(int tabSize) {
153             this.tabSize = tabSize;
154         }
155
156         /** Mark that first call will follow */
157         public void reset() {
158             super.reset();
159             curVisCol = 0;
160         }
161
162         /** finds BOL on current line */
163         public int find(int bufferStartPos, char buffer[],
164                         int offset1, int offset2, int reqPos, int limitPos) {
165
166             int offset = reqPos - bufferStartPos;
167             while (offset < offset2) {
168                 if (curVisCol >= visCol) {
169                     found = true;
170                     return bufferStartPos + offset;
171                 }
172
173                 switch (buffer[offset]) {
174                 case '\t':
175                     curVisCol = (curVisCol + tabSize) / tabSize * tabSize;
176                     break;
177                 case '\n':
178                     found = true;
179                     return bufferStartPos + offset;
180                 default:
181                     curVisCol++;
182                 }
183                 offset++;
184             }
185             return bufferStartPos + offset;
186         }
187
188     }
189
190     /** Generic forward finder that simplifies the search process. */
191     public static abstract class GenericFwdFinder extends AbstractFinder {
192
193         public final int find(int bufferStartPos, char buffer[],
194                               int offset1, int offset2, int reqPos, int limitPos) {
195             int offset = reqPos - bufferStartPos;
196             int limitOffset = limitPos - bufferStartPos - 1;
197             while (offset >= offset1 && offset < offset2) {
198                 offset += scan(buffer[offset], (offset == limitOffset));
199                 if (found) {
200                     break;
201                 }
202             }
203             return bufferStartPos + offset;
204         }
205
206         /** This function decides if it found a desired string or not.
207         * The function receives currently searched character and flag if it's
208         * the last one that is searched or not.
209         * @return if the function decides that
210         * it found a desired string it sets <CODE>found = true</CODE> and returns
211         * how many characters back the searched string begins in forward
212         * direction (0 stands for current character).
213         * For example if the function looks for word 'yes' and it gets
214         * 's' as parameter it sets found = true and returns -2.
215         * If the string is not yet found it returns how many characters it should go
216         * in forward direction (in this case it would usually be 1).
217         * The next searched character will be that one requested.
218         */

219         protected abstract int scan(char ch, boolean lastChar);
220
221     }
222
223     /** Generic backward finder that simplifies the search process. */
224     public static abstract class GenericBwdFinder extends AbstractFinder {
225
226         public final int find(int bufferStartPos, char buffer[],
227                               int offset1, int offset2, int reqPos, int limitPos) {
228             int offset = reqPos - bufferStartPos;
229             int limitOffset = limitPos - bufferStartPos;
230             while (offset >= offset1 && offset < offset2) {
231                 offset += scan(buffer[offset], (offset == limitOffset));
232                 if (found) {
233                     break;
234                 }
235             }
236             return bufferStartPos + offset;
237         }
238
239         /** This function decides if it found a desired string or not.
240         * The function receives currently searched character and flag if it's
241         * the last one that is searched or not.
242         * @return if the function decides that
243         * it found a desired string it sets <CODE>found = true</CODE> and returns
244         * how many characters back the searched string begins in backward
245         * direction (0 stands for current character). It is usually 0 as the
246         * finder usually decides after the last required character but it's
247         * not always the case e.g. for whole-words-only search it can be 1 or so.
248         * If the string is not yet found it returns how many characters it should go
249         * in backward direction (in this case it would usually be -1).
250         * The next searched character will be that one requested.
251         */

252         protected abstract int scan(char ch, boolean lastChar);
253
254     }
255
256     public static abstract class GenericFinder extends AbstractFinder {
257
258         /** Flag that determines whether the search is in the forward direction */
259         protected boolean forward;
260
261         public boolean isForward() {
262             return forward;
263         }
264
265         public final int find(int bufferStartPos, char buffer[],
266                               int offset1, int offset2, int reqPos, int limitPos) {
267             int offset = reqPos - bufferStartPos;
268             int limitOffset = limitPos - bufferStartPos;
269             if (forward) {
270                 limitOffset--; // decrease limit offset for the forward search
271
}
272             while (offset >= offset1 && offset < offset2) {
273                 offset += scan(buffer[offset], (offset == limitOffset));
274                 if (found) {
275                     break;
276                 }
277             }
278             return bufferStartPos + offset;
279         }
280
281         /** The method that gets the actual character and whether
282         * that character is the last in the search. It can
283         * generally set the found flag to true to signal the successive
284         * search or it can return positive number to go forward
285         * or negative number to go back.
286         */

287         protected abstract int scan(char ch, boolean lastChar);
288     }
289
290     /** Searches for the specified char in forward direction. */
291     public static class CharFwdFinder extends GenericFwdFinder {
292
293         char searchChar;
294
295         public CharFwdFinder(char searchChar) {
296             this.searchChar = searchChar;
297         }
298
299         protected int scan(char ch, boolean lastChar) {
300             if (ch == searchChar) {
301                 found = true;
302                 return 0;
303             }
304             return +1;
305         }
306
307     }
308
309     /** Searches for the specified char in backward direction. */
310     public static class CharBwdFinder extends GenericBwdFinder {
311
312         char searchChar;
313
314         public CharBwdFinder(char searchChar) {
315             this.searchChar = searchChar;
316         }
317
318         protected int scan(char ch, boolean lastChar) {
319             if (ch == searchChar) {
320                 found = true;
321                 return 0;
322             }
323             return -1;
324         }
325
326     }
327
328     /** Searches for anyone of the specified chars in forward direction. */
329     public static class CharArrayFwdFinder extends GenericFwdFinder {
330
331         char searchChars[];
332
333         char foundChar;
334
335         public CharArrayFwdFinder(char searchChars[]) {
336             this.searchChars = searchChars;
337         }
338
339         protected int scan(char ch, boolean lastChar) {
340             for (int i = 0; i < searchChars.length; i++) {
341                 if (ch == searchChars[i]) {
342                     foundChar = searchChars[i];
343                     found = true;
344                     return 0;
345                 }
346             }
347             return +1;
348         }
349
350         public char getFoundChar() {
351             return foundChar;
352         }
353
354     }
355
356     public static class AcceptorFwdFinder extends GenericFwdFinder {
357
358         Acceptor a;
359
360         public AcceptorFwdFinder(Acceptor a) {
361             this.a = a;
362         }
363
364         protected int scan(char ch, boolean lastChar) {
365             if (!a.accept(ch)) {
366                 found = true;
367                 return 0;
368             }
369             return +1;
370         }
371
372     }
373
374     /** Searches for anyone of the specified chars in backward direction. */
375     public static class CharArrayBwdFinder extends GenericBwdFinder {
376
377         char searchChars[];
378
379         char foundChar;
380
381         public CharArrayBwdFinder(char searchChars[]) {
382             this.searchChars = searchChars;
383         }
384
385         protected int scan(char ch, boolean lastChar) {
386             for (int i = 0; i < searchChars.length; i++) {
387                 if (ch == searchChars[i]) {
388                     foundChar = searchChars[i];
389                     found = true;
390                     return 0;
391                 }
392             }
393             return -1;
394         }
395
396         public char getFoundChar() {
397             return foundChar;
398         }
399
400     }
401
402     public static class AcceptorBwdFinder extends GenericBwdFinder {
403
404         Acceptor a;
405
406         public AcceptorBwdFinder(Acceptor a) {
407             this.a = a;
408         }
409
410         protected int scan(char ch, boolean lastChar) {
411             if (!a.accept(ch)) {
412                 found = true;
413                 return 0;
414             }
415             return -1;
416         }
417
418     }
419
420     /** Next word forward finder */
421     public static class NextWordFwdFinder extends GenericFwdFinder {
422
423         /** Document used to recognize the character types */
424         BaseDocument doc;
425
426         /** Currently inside whitespace */
427         boolean inWhitespace;
428
429         /** Currently inside identifier */
430         boolean inIdentifier;
431
432         /** Currently inside not in word and not in whitespace */
433         boolean inPunct;
434
435         /** Whether scanning the first character */
436         boolean firstChar;
437
438         /** Whether stop on EOL */
439         boolean stopOnEOL;
440
441         /** Stop with successful find on the first white character */
442         boolean stopOnWhitespace;
443
444         public NextWordFwdFinder(BaseDocument doc, boolean stopOnEOL, boolean stopOnWhitespace) {
445             this.doc = doc;
446             this.stopOnEOL = stopOnEOL;
447             this.stopOnWhitespace = stopOnWhitespace;
448         }
449
450         public void reset() {
451             super.reset();
452             inWhitespace = false;
453             inIdentifier = false;
454             inPunct = false;
455             firstChar = true;
456         }
457
458         protected int scan(char ch, boolean lastChar) {
459             if (stopOnEOL) {
460                 if (ch == '\n') {
461                     found = true;
462                     return firstChar ? 1 : 0;
463                 }
464                 firstChar = false;
465             }
466
467             if (doc.isWhitespace(ch)) { // whitespace char found
468
if (stopOnWhitespace) {
469                     found = true;
470                     return 0;
471                 } else {
472                     inWhitespace = true;
473                     return 1;
474                 }
475             }
476
477             if (inWhitespace) {
478                 found = true;
479                 return 0;
480             }
481             if (inIdentifier) { // inside word
482
if (doc.isIdentifierPart(ch)) { // still in word
483
return 1;
484                 }
485                 found = true;
486                 return 0; // found punct
487
}
488             if (inPunct) { // inside punctuation
489
if (doc.isIdentifierPart(ch)) { // a word starts after punct
490
found = true;
491                     return 0;
492                 }
493                 return 1; // still in punct
494
}
495
496             // just starting - no state assigned yet
497
if (doc.isIdentifierPart(ch)) {
498                 inIdentifier = true;
499                 return 1;
500             } else {
501                 inPunct = true;
502                 return 1;
503             }
504         }
505
506     }
507
508     /** Find start of the word. This finder can be used to go to previous
509     * word or to the start of the current word.
510     */

511     public static class PreviousWordBwdFinder extends GenericBwdFinder {
512
513         BaseDocument doc;
514
515         /** Currently inside identifier */
516         boolean inIdentifier;
517
518         /** Currently inside not in word and not in whitespace */
519         boolean inPunct;
520
521         /** Stop on EOL */
522         boolean stopOnEOL;
523
524         /** Stop with successful find on the first white character */
525         boolean stopOnWhitespace;
526
527         boolean firstChar;
528
529         public PreviousWordBwdFinder(BaseDocument doc, boolean stopOnEOL, boolean stopOnWhitespace) {
530             this.doc = doc;
531             this.stopOnEOL = stopOnEOL;
532             this.stopOnWhitespace = stopOnWhitespace;
533         }
534
535         public void reset() {
536             super.reset();
537             inIdentifier = false;
538             inPunct = false;
539             firstChar = true;
540         }
541
542         protected int scan(char ch, boolean lastChar) {
543             if (stopOnEOL) {
544                 if (ch == '\n') {
545                     found = true;
546                     return firstChar ? 0 : 1;
547                 }
548                 firstChar = false;
549             }
550
551             if (inIdentifier) { // inside word
552
if (doc.isIdentifierPart(ch)) {
553                     if (lastChar) {
554                         found = true;
555                         return 0;
556                     }
557                     return -1;
558                 }
559                 found = true;
560                 return 1; // found punct or whitespace
561
}
562             if (inPunct) { // inside punctuation
563
if (doc.isIdentifierPart(ch) || doc.isWhitespace(ch) || lastChar) {
564                     found = true;
565                     return 1;
566                 }
567                 return -1; // still in punct
568
}
569             if (doc.isWhitespace(ch)) {
570                 if (stopOnWhitespace) {
571                     found = true;
572                     return 1;
573                 }
574                 return -1;
575             }
576             if (doc.isIdentifierPart(ch)) {
577                 inIdentifier = true;
578                 if (lastChar) {
579                     found = true;
580                     return 0;
581                 }
582                 return -1;
583             }
584             inPunct = true;
585             return -1;
586         }
587
588     }
589
590     /** Find first white character forward */
591     public static class WhiteFwdFinder extends GenericFwdFinder {
592
593         BaseDocument doc;
594
595         private char foundChar;
596
597         public WhiteFwdFinder(BaseDocument doc) {
598             this.doc = doc;
599         }
600
601         public char getFoundChar() {
602             return foundChar;
603         }
604
605         protected int scan(char ch, boolean lastChar) {
606             if (doc.isWhitespace(ch)) {
607                 found = true;
608                 foundChar = ch;
609                 return 0;
610             }
611             return 1;
612         }
613     }
614
615     /** Find first white character backward */
616     public static class WhiteBwdFinder extends GenericBwdFinder {
617
618         BaseDocument doc;
619
620         private char foundChar;
621
622         public WhiteBwdFinder(BaseDocument doc) {
623             this.doc = doc;
624         }
625
626         public char getFoundChar() {
627             return foundChar;
628         }
629
630         protected int scan(char ch, boolean lastChar) {
631             if (doc.isWhitespace(ch)) {
632                 found = true;
633                 foundChar = ch;
634                 return 0;
635             }
636             return -1;
637         }
638     }
639
640     /** Find first non-white character forward */
641     public static class NonWhiteFwdFinder extends GenericFwdFinder {
642
643         BaseDocument doc;
644
645         private char foundChar;
646
647         public NonWhiteFwdFinder(BaseDocument doc) {
648             this.doc = doc;
649         }
650
651         public char getFoundChar() {
652             return foundChar;
653         }
654
655         protected int scan(char ch, boolean lastChar) {
656             if (!doc.isWhitespace(ch)) {
657                 found = true;
658                 foundChar = ch;
659                 return 0;
660             }
661             return 1;
662         }
663     }
664
665     /** Find first non-white character backward */
666     public static class NonWhiteBwdFinder extends GenericBwdFinder {
667
668         BaseDocument doc;
669
670         private char foundChar;
671
672         public NonWhiteBwdFinder(BaseDocument doc) {
673             this.doc = doc;
674         }
675
676         public char getFoundChar() {
677             return foundChar;
678         }
679
680         protected int scan(char ch, boolean lastChar) {
681             if (!doc.isWhitespace(ch)) {
682                 found = true;
683                 foundChar = ch;
684                 return 0;
685             }
686             return -1;
687         }
688     }
689
690     /** String forward finder */
691     public static final class StringFwdFinder extends GenericFwdFinder
692         implements StringFinder {
693
694         char chars[];
695
696         int stringInd;
697
698         boolean matchCase;
699
700         public StringFwdFinder(String JavaDoc s, boolean matchCase) {
701             this.matchCase = matchCase;
702             chars = (matchCase ? s : s.toLowerCase()).toCharArray();
703         }
704
705         public int getFoundLength() {
706             return chars.length;
707         }
708
709         public void reset() {
710             super.reset();
711             stringInd = 0;
712         }
713
714         protected int scan(char ch, boolean lastChar) {
715             if (!matchCase) {
716                 ch = Character.toLowerCase(ch);
717             }
718             if (ch == chars[stringInd]) {
719                 stringInd++;
720                 if (stringInd == chars.length) { // found whole string
721
found = true;
722                     return 1 - stringInd; // how many chars back the string starts
723
}
724                 return 1; // successfully matched char, go to next char
725
} else {
726                 if (stringInd == 0) {
727                     return 1;
728                 } else {
729                     int back = 1 - stringInd;
730                     stringInd = 0;
731                     return back;
732                 }
733             }
734         }
735
736     }
737
738     /** String backward finder */
739     public static class StringBwdFinder extends GenericBwdFinder
740         implements StringFinder {
741
742         char chars[];
743
744         int stringInd;
745
746         boolean matchCase;
747
748         int endInd;
749
750         public StringBwdFinder(String JavaDoc s, boolean matchCase) {
751             this.matchCase = matchCase;
752             chars = (matchCase ? s : s.toLowerCase()).toCharArray();
753             endInd = chars.length - 1;
754         }
755
756         public int getFoundLength() {
757             return chars.length;
758         }
759
760         public void reset() {
761             super.reset();
762             stringInd = endInd;
763         }
764
765         protected int scan(char ch, boolean lastChar) {
766             if (!matchCase) {
767                 ch = Character.toLowerCase(ch);
768             }
769             if (ch == chars[stringInd]) {
770                 stringInd--;
771                 if (stringInd == -1) {
772                     found = true;
773                     return 0;
774                 }
775                 return -1;
776             } else {
777                 if (stringInd == endInd) {
778                     return -1;
779                 } else {
780                     int back = chars.length - 2 - stringInd;
781                     stringInd = endInd;
782                     return back;
783                 }
784             }
785         }
786
787     }
788
789     /** String forward finder that finds whole words only.
790     * There are some speed optimizations attempted.
791     */

792     public static final class WholeWordsFwdFinder extends GenericFwdFinder
793         implements StringFinder {
794
795         char chars[];
796
797         int stringInd;
798
799         boolean matchCase;
800
801         BaseDocument doc;
802
803         boolean insideWord;
804
805         boolean firstCharWordPart;
806
807         boolean wordFound;
808
809         public WholeWordsFwdFinder(BaseDocument doc, String JavaDoc s, boolean matchCase) {
810             this.doc = doc;
811             this.matchCase = matchCase;
812             chars = (matchCase ? s : s.toLowerCase()).toCharArray();
813             firstCharWordPart = doc.isIdentifierPart(chars[0]);
814         }
815
816         public int getFoundLength() {
817             return chars.length;
818         }
819
820         public void reset() {
821             super.reset();
822             insideWord = false;
823             wordFound = false;
824             stringInd = 0;
825         }
826
827         protected int scan(char ch, boolean lastChar) {
828             if (!matchCase) {
829                 ch = Character.toLowerCase(ch);
830             }
831
832             // whole word already found but must verify next char
833
if (wordFound) {
834                 if (doc.isIdentifierPart(ch)) { // word continues
835
wordFound = false;
836                     insideWord = firstCharWordPart;
837                     stringInd = 0;
838                     return 1 - chars.length;
839                 } else {
840                     found = true;
841                     return -chars.length;
842                 }
843             }
844
845             if (stringInd == 0) { // special case for first char
846
if (ch != chars[0] || insideWord) { // first char doesn't match
847
insideWord = doc.isIdentifierPart(ch);
848                     return 1;
849                 } else { // first char matches
850
stringInd = 1; // matched and not inside word
851
if (chars.length == 1) {
852                         if (lastChar) {
853                             found = true;
854                             return 0;
855                         } else {
856                             wordFound = true;
857                             return 1;
858                         }
859                     }
860                     return 1;
861                 }
862             } else { // already matched at least one char
863
if (ch == chars[stringInd]) { // matches current char
864
stringInd++;
865                     if (stringInd == chars.length) { // found whole string
866
if (lastChar) {
867                             found = true;
868                             return 1 - chars.length; // how many chars back the string starts
869
} else {
870                             wordFound = true;
871                             return 1;
872                         }
873                     }
874                     return 1; // successfully matched char, go to next char
875
} else { // current char doesn't match, stringInd > 0
876
int back = 1 - stringInd;
877                     stringInd = 0;
878                     insideWord = firstCharWordPart;
879                     return back; // go back to search from the next to first char
880
}
881             }
882         }
883
884     }
885
886     /** String backward finder that finds whole words only.
887     * There are some speed optimizations attemted.
888     */

889     public static final class WholeWordsBwdFinder extends GenericBwdFinder
890         implements StringFinder {
891
892         char chars[];
893
894         int stringInd;
895
896         boolean matchCase;
897
898         boolean insideWord;
899
900         boolean lastCharWordPart;
901
902         boolean wordFound;
903
904         int endInd;
905
906         BaseDocument doc;
907
908         public WholeWordsBwdFinder(BaseDocument doc, String JavaDoc s, boolean matchCase) {
909             this.doc = doc;
910             this.matchCase = matchCase;
911             chars = (matchCase ? s : s.toLowerCase()).toCharArray();
912             endInd = chars.length - 1;
913             doc.isIdentifierPart(chars[endInd]);
914         }
915
916         public int getFoundLength() {
917             return chars.length;
918         }
919
920         public void reset() {
921             super.reset();
922             insideWord = false;
923             wordFound = false;
924             stringInd = endInd;
925         }
926
927         protected int scan(char ch, boolean lastChar) {
928             if (!matchCase) {
929                 ch = Character.toLowerCase(ch);
930             }
931
932             // whole word already found but must verify next char
933
if (wordFound) {
934                 if (doc.isIdentifierPart(ch)) { // word continues
935
wordFound = false;
936                     insideWord = lastCharWordPart;
937                     stringInd = endInd;
938                     return endInd;
939                 } else {
940                     found = true;
941                     return 1;
942                 }
943             }
944
945             if (stringInd == endInd) { // special case for last char
946
if (ch != chars[endInd] || insideWord) { // first char doesn't match
947
insideWord = doc.isIdentifierPart(ch);
948                     return -1;
949                 } else { // first char matches
950
stringInd = endInd - 1; // matched and not inside word
951
if (chars.length == 1) {
952                         if (lastChar) {
953                             found = true;
954                             return 0;
955                         } else {
956                             wordFound = true;
957                             return -1;
958                         }
959                     }
960                     return -1;
961                 }
962             } else { // already matched at least one char
963
if (ch == chars[stringInd]) { // matches current char
964
stringInd--;
965                     if (stringInd == -1) { // found whole string
966
if (lastChar) {
967                             found = true;
968                             return 0;
969                         } else {
970                             wordFound = true;
971                             return -1;
972                         }
973                     }
974                     return -1; // successfully matched char, go to next char
975
} else { // current char doesn't match, stringInd > 0
976
int back = chars.length - 2 - stringInd;
977                     stringInd = endInd;
978                     insideWord = lastCharWordPart;
979                     return back;
980                 }
981             }
982         }
983     }
984
985     /** Support for creating blocks finders. */
986     public static abstract class AbstractBlocksFinder extends AbstractFinder
987         implements BlocksFinder {
988
989         private static int[] EMPTY_INT_ARRAY = new int[0];
990
991         private int[] blocks = EMPTY_INT_ARRAY;
992
993         private int blocksInd;
994
995         private boolean closed;
996
997         public void reset() {
998             blocksInd = 0;
999             closed = false;
1000        }
1001
1002        public int[] getBlocks() {
1003            if (!closed) { // not closed yet
1004
closeBlocks();
1005                closed = true;
1006            }
1007            return blocks;
1008        }
1009
1010        public void setBlocks(int[] blocks) {
1011            this.blocks = blocks;
1012            closed = false;
1013        }
1014
1015        protected void addBlock(int blkStartPos, int blkEndPos) {
1016            if (blocksInd == blocks.length) {
1017                int[] dbl = new int[blocks.length * 2];
1018                System.arraycopy(blocks, 0, dbl, 0, blocks.length);
1019                blocks = dbl;
1020            }
1021            blocks[blocksInd++] = blkStartPos;
1022            blocks[blocksInd++] = blkEndPos;
1023        }
1024
1025        /** Insert closing sequence [-1, -1] */
1026        protected void closeBlocks() {
1027            addBlock(-1, -1);
1028        }
1029
1030        public String JavaDoc debugBlocks() {
1031            StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1032            int ind = 0;
1033            while (blocks[ind] != -1) {
1034                buf.append((ind/2 + 1) + ": [" + blocks[ind] + ", " + blocks[ind + 1] + "]\n"); // NOI18N
1035
ind+= 2;
1036            }
1037            return buf.toString();
1038        }
1039
1040    }
1041
1042    public static final class FalseBlocksFinder extends AbstractBlocksFinder {
1043
1044        public int find(int bufferStartPos, char buffer[],
1045                        int offset1, int offset2, int reqPos, int limitPos) {
1046            return -1;
1047        }
1048
1049    }
1050
1051    /** String forward finder that creates position blocks */
1052    public static final class StringBlocksFinder
1053        extends AbstractBlocksFinder {
1054
1055        char chars[];
1056
1057        int stringInd;
1058
1059        boolean matchCase;
1060
1061        public StringBlocksFinder(String JavaDoc s, boolean matchCase) {
1062            this.matchCase = matchCase;
1063            chars = (matchCase ? s : s.toLowerCase()).toCharArray();
1064        }
1065
1066        public void reset() {
1067            super.reset();
1068            stringInd = 0;
1069        }
1070
1071        public int find(int bufferStartPos, char buffer[],
1072                        int offset1, int offset2, int reqPos, int limitPos) {
1073            int offset = reqPos - bufferStartPos;
1074            while (offset >= offset1 && offset < offset2) {
1075                char ch = buffer[offset];
1076
1077                if (!matchCase) {
1078                    ch = Character.toLowerCase(ch);
1079                }
1080                if (ch == chars[stringInd]) {
1081                    stringInd++;
1082                    if (stringInd == chars.length) {
1083                        int blkEnd = bufferStartPos + offset + 1;
1084                        addBlock(blkEnd - stringInd, blkEnd);
1085                        stringInd = 0;
1086                    }
1087                    offset++;
1088                } else {
1089                    offset += 1 - stringInd;
1090                    stringInd = 0;
1091                }
1092
1093            }
1094            reqPos = bufferStartPos + offset;
1095            return reqPos;
1096        }
1097
1098    }
1099
1100    /** String forward finder that finds whole words only
1101    * and that creates position blocks.
1102    * There are some speed optimizations attempted.
1103    */

1104    public static final class WholeWordsBlocksFinder extends AbstractBlocksFinder {
1105
1106        char chars[];
1107
1108        int stringInd;
1109
1110        boolean matchCase;
1111
1112        boolean insideWord;
1113
1114        boolean firstCharWordPart;
1115
1116        boolean wordFound;
1117
1118        BaseDocument doc;
1119
1120        public WholeWordsBlocksFinder(BaseDocument doc, String JavaDoc s, boolean matchCase) {
1121            this.doc = doc;
1122            this.matchCase = matchCase;
1123            chars = (matchCase ? s : s.toLowerCase()).toCharArray();
1124            firstCharWordPart = doc.isIdentifierPart(chars[0]);
1125        }
1126
1127        public void reset() {
1128            super.reset();
1129            insideWord = false;
1130            wordFound = false;
1131            stringInd = 0;
1132        }
1133
1134        public int find(int bufferStartPos, char buffer[],
1135                        int offset1, int offset2, int reqPos, int limitPos) {
1136            int offset = reqPos - bufferStartPos;
1137            int limitOffset = limitPos - bufferStartPos - 1;
1138            while (offset >= offset1 && offset < offset2) {
1139                char ch = buffer[offset];
1140
1141                if (!matchCase) {
1142                    ch = Character.toLowerCase(ch);
1143                }
1144
1145                // whole word already found but must verify next char
1146
if (wordFound) {
1147                    if (doc.isIdentifierPart(ch)) { // word continues
1148
insideWord = firstCharWordPart;
1149                        offset -= chars.length - 1;
1150                    } else {
1151                        int blkEnd = bufferStartPos + offset;
1152                        addBlock(blkEnd - chars.length, blkEnd);
1153                        insideWord = false;
1154                        offset++;
1155                    }
1156                    wordFound = false;
1157                    stringInd = 0;
1158                    continue;
1159                }
1160
1161                if (stringInd == 0) { // special case for first char
1162
if (ch != chars[0] || insideWord) { // first char doesn't match
1163
insideWord = doc.isIdentifierPart(ch);
1164                        offset++;
1165                    } else { // first char matches
1166
stringInd = 1; // matched and not inside word
1167
if (chars.length == 1) {
1168                            if (offset == limitOffset) {
1169                                int blkStart = bufferStartPos + offset;
1170                                addBlock(blkStart, blkStart + 1);
1171                            } else {
1172                                wordFound = true;
1173                            }
1174                        }
1175                        offset++;
1176                    }
1177                } else { // already matched at least one char
1178
if (ch == chars[stringInd]) { // matches current char
1179
stringInd++;
1180                        if (stringInd == chars.length) { // found whole string
1181
if (offset == limitOffset) {
1182                                int blkEnd = bufferStartPos + 1;
1183                                addBlock(blkEnd - stringInd, blkEnd);
1184                            } else {
1185                                wordFound = true;
1186                            }
1187                        }
1188                        offset++;
1189                    } else { // current char doesn't match, stringInd > 0
1190
offset += 1 - stringInd;
1191                        stringInd = 0;
1192                        insideWord = firstCharWordPart;
1193                    }
1194                }
1195
1196            }
1197            reqPos = bufferStartPos + offset;
1198            return reqPos;
1199        }
1200
1201    }
1202
1203    /** Finder that looks for some search expression expressed by string.
1204    * It can be either simple string
1205    * or some form of regular expression expressed by string.
1206    */

1207    public interface StringFinder extends Finder {
1208
1209        /** Get the length of the found string. This is useful
1210        * for regular expressions, because the length of the regular
1211        * expression can be different than the length of the string
1212        * that matched the expression.
1213        */

1214        public int getFoundLength();
1215
1216    }
1217
1218    /** Finder that constructs [begin-pos, end-pos] blocks.
1219    * This is useful for highlight-search draw layer.
1220    * The block-finders are always forward-search finders.
1221    */

1222    public interface BlocksFinder extends Finder {
1223
1224        /** Set the array into which the finder puts
1225        * the position blocks. If the length of array is not sufficient
1226        * the finder extends the array. The last block is set to [-1, -1].
1227        */

1228        public void setBlocks(int[] blocks);
1229
1230        /** Get the array filled with position blocks. It is either
1231        * original array passed to setBlocks() or the new array
1232        * if the finder extended the array.
1233        */

1234        public int[] getBlocks();
1235
1236    }
1237
1238
1239}
1240
Popular Tags