Revision 4890
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/JavaScriptTokenMarker.java | ||
---|---|---|
1 |
package com.iver.utiles.console.jedit; |
|
2 |
/* |
|
3 |
* JavaScriptTokenMarker.java - JavaScript token marker |
|
4 |
* Copyright (C) 1999 Slava Pestov |
|
5 |
* |
|
6 |
* You may use and modify this package for any purpose. Redistribution is |
|
7 |
* permitted, in both source and binary form, provided that this notice |
|
8 |
* remains intact in all source distributions of this package. |
|
9 |
*/ |
|
10 |
|
|
11 |
import javax.swing.text.Segment; |
|
12 |
|
|
13 |
/** |
|
14 |
* JavaScript token marker. |
|
15 |
* |
|
16 |
* @author Slava Pestov |
|
17 |
* @version $Id$ |
|
18 |
*/ |
|
19 |
public class JavaScriptTokenMarker extends CTokenMarker |
|
20 |
{ |
|
21 |
public JavaScriptTokenMarker() |
|
22 |
{ |
|
23 |
super(false,getKeywords()); |
|
24 |
} |
|
25 |
|
|
26 |
public static KeywordMap getKeywords() |
|
27 |
{ |
|
28 |
if(javaScriptKeywords == null) |
|
29 |
{ |
|
30 |
javaScriptKeywords = new KeywordMap(false); |
|
31 |
javaScriptKeywords.add("function",Token.KEYWORD3); |
|
32 |
javaScriptKeywords.add("var",Token.KEYWORD3); |
|
33 |
javaScriptKeywords.add("else",Token.KEYWORD1); |
|
34 |
javaScriptKeywords.add("for",Token.KEYWORD1); |
|
35 |
javaScriptKeywords.add("if",Token.KEYWORD1); |
|
36 |
javaScriptKeywords.add("in",Token.KEYWORD1); |
|
37 |
javaScriptKeywords.add("new",Token.KEYWORD1); |
|
38 |
javaScriptKeywords.add("return",Token.KEYWORD1); |
|
39 |
javaScriptKeywords.add("while",Token.KEYWORD1); |
|
40 |
javaScriptKeywords.add("with",Token.KEYWORD1); |
|
41 |
javaScriptKeywords.add("break",Token.KEYWORD1); |
|
42 |
javaScriptKeywords.add("case",Token.KEYWORD1); |
|
43 |
javaScriptKeywords.add("continue",Token.KEYWORD1); |
|
44 |
javaScriptKeywords.add("default",Token.KEYWORD1); |
|
45 |
javaScriptKeywords.add("false",Token.LABEL); |
|
46 |
javaScriptKeywords.add("this",Token.LABEL); |
|
47 |
javaScriptKeywords.add("true",Token.LABEL); |
|
48 |
} |
|
49 |
return javaScriptKeywords; |
|
50 |
} |
|
51 |
|
|
52 |
// private members |
|
53 |
private static KeywordMap javaScriptKeywords; |
|
54 |
} |
|
0 | 55 |
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/IDLTokenMarker.java | ||
---|---|---|
1 |
package com.iver.utiles.console.jedit; |
|
2 |
/* |
|
3 |
* IDLTokenMarker.java - IDL token marker |
|
4 |
* Copyright (C) 1999 Slava Pestov |
|
5 |
* Copyright (C) 1999 Juha Lindfors |
|
6 |
* |
|
7 |
* You may use and modify this package for any purpose. Redistribution is |
|
8 |
* permitted, in both source and binary form, provided that this notice |
|
9 |
* remains intact in all source distributions of this package. |
|
10 |
*/ |
|
11 |
|
|
12 |
import javax.swing.text.Segment; |
|
13 |
|
|
14 |
/** |
|
15 |
* IDL token marker. |
|
16 |
* |
|
17 |
* @author Slava Pestov |
|
18 |
* @author Juha Lindfors |
|
19 |
* @version $Id$ |
|
20 |
*/ |
|
21 |
public class IDLTokenMarker extends CTokenMarker |
|
22 |
{ |
|
23 |
public IDLTokenMarker() |
|
24 |
{ |
|
25 |
super(true,getKeywords()); |
|
26 |
} |
|
27 |
|
|
28 |
public static KeywordMap getKeywords() |
|
29 |
{ |
|
30 |
if(idlKeywords == null) |
|
31 |
{ |
|
32 |
idlKeywords = new KeywordMap(false); |
|
33 |
|
|
34 |
idlKeywords.add("any", Token.KEYWORD3); |
|
35 |
idlKeywords.add("attribute",Token.KEYWORD1); |
|
36 |
idlKeywords.add("boolean", Token.KEYWORD3); |
|
37 |
idlKeywords.add("case", Token.KEYWORD1); |
|
38 |
idlKeywords.add("char", Token.KEYWORD3); |
|
39 |
idlKeywords.add("const", Token.KEYWORD1); |
|
40 |
idlKeywords.add("context", Token.KEYWORD1); |
|
41 |
idlKeywords.add("default", Token.KEYWORD1); |
|
42 |
idlKeywords.add("double", Token.KEYWORD3); |
|
43 |
idlKeywords.add("enum", Token.KEYWORD3); |
|
44 |
idlKeywords.add("exception",Token.KEYWORD1); |
|
45 |
idlKeywords.add("FALSE", Token.LITERAL2); |
|
46 |
idlKeywords.add("fixed", Token.KEYWORD1); |
|
47 |
idlKeywords.add("float", Token.KEYWORD3); |
|
48 |
idlKeywords.add("in", Token.KEYWORD1); |
|
49 |
idlKeywords.add("inout", Token.KEYWORD1); |
|
50 |
idlKeywords.add("interface",Token.KEYWORD1); |
|
51 |
idlKeywords.add("long", Token.KEYWORD3); |
|
52 |
idlKeywords.add("module", Token.KEYWORD1); |
|
53 |
idlKeywords.add("Object", Token.KEYWORD3); |
|
54 |
idlKeywords.add("octet", Token.KEYWORD3); |
|
55 |
idlKeywords.add("oneway", Token.KEYWORD1); |
|
56 |
idlKeywords.add("out", Token.KEYWORD1); |
|
57 |
idlKeywords.add("raises", Token.KEYWORD1); |
|
58 |
idlKeywords.add("readonly", Token.KEYWORD1); |
|
59 |
idlKeywords.add("sequence", Token.KEYWORD3); |
|
60 |
idlKeywords.add("short", Token.KEYWORD3); |
|
61 |
idlKeywords.add("string", Token.KEYWORD3); |
|
62 |
idlKeywords.add("struct", Token.KEYWORD3); |
|
63 |
idlKeywords.add("switch", Token.KEYWORD1); |
|
64 |
idlKeywords.add("TRUE", Token.LITERAL2); |
|
65 |
idlKeywords.add("typedef", Token.KEYWORD3); |
|
66 |
idlKeywords.add("unsigned", Token.KEYWORD3); |
|
67 |
idlKeywords.add("union", Token.KEYWORD3); |
|
68 |
idlKeywords.add("void", Token.KEYWORD3); |
|
69 |
idlKeywords.add("wchar", Token.KEYWORD3); |
|
70 |
idlKeywords.add("wstring", Token.KEYWORD3); |
|
71 |
} |
|
72 |
return idlKeywords; |
|
73 |
} |
|
74 |
|
|
75 |
// private members |
|
76 |
private static KeywordMap idlKeywords; |
|
77 |
} |
|
0 | 78 |
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/MakefileTokenMarker.java | ||
---|---|---|
1 |
package com.iver.utiles.console.jedit; |
|
2 |
/* |
|
3 |
* MakefileTokenMarker.java - Makefile token marker |
|
4 |
* Copyright (C) 1998, 1999 Slava Pestov |
|
5 |
* |
|
6 |
* You may use and modify this package for any purpose. Redistribution is |
|
7 |
* permitted, in both source and binary form, provided that this notice |
|
8 |
* remains intact in all source distributions of this package. |
|
9 |
*/ |
|
10 |
|
|
11 |
import javax.swing.text.Segment; |
|
12 |
|
|
13 |
/** |
|
14 |
* Makefile token marker. |
|
15 |
* |
|
16 |
* @author Slava Pestov |
|
17 |
* @version $Id$ |
|
18 |
*/ |
|
19 |
public class MakefileTokenMarker extends TokenMarker |
|
20 |
{ |
|
21 |
// public members |
|
22 |
public byte markTokensImpl(byte token, Segment line, int lineIndex) |
|
23 |
{ |
|
24 |
char[] array = line.array; |
|
25 |
int offset = line.offset; |
|
26 |
int lastOffset = offset; |
|
27 |
int length = line.count + offset; |
|
28 |
boolean backslash = false; |
|
29 |
loop: for(int i = offset; i < length; i++) |
|
30 |
{ |
|
31 |
int i1 = (i+1); |
|
32 |
|
|
33 |
char c = array[i]; |
|
34 |
if(c == '\\') |
|
35 |
{ |
|
36 |
backslash = !backslash; |
|
37 |
continue; |
|
38 |
} |
|
39 |
|
|
40 |
switch(token) |
|
41 |
{ |
|
42 |
case Token.NULL: |
|
43 |
switch(c) |
|
44 |
{ |
|
45 |
case ':': case '=': case ' ': case '\t': |
|
46 |
backslash = false; |
|
47 |
if(lastOffset == offset) |
|
48 |
{ |
|
49 |
addToken(i1 - lastOffset,Token.KEYWORD1); |
|
50 |
lastOffset = i1; |
|
51 |
} |
|
52 |
break; |
|
53 |
case '#': |
|
54 |
if(backslash) |
|
55 |
backslash = false; |
|
56 |
else |
|
57 |
{ |
|
58 |
addToken(i - lastOffset,token); |
|
59 |
addToken(length - i,Token.COMMENT1); |
|
60 |
lastOffset = length; |
|
61 |
break loop; |
|
62 |
} |
|
63 |
break; |
|
64 |
case '$': |
|
65 |
if(backslash) |
|
66 |
backslash = false; |
|
67 |
else if(lastOffset != offset) |
|
68 |
{ |
|
69 |
addToken(i - lastOffset,token); |
|
70 |
lastOffset = i; |
|
71 |
if(length - i > 1) |
|
72 |
{ |
|
73 |
char c1 = array[i1]; |
|
74 |
if(c1 == '(' || c1 == '{') |
|
75 |
token = Token.KEYWORD2; |
|
76 |
else |
|
77 |
{ |
|
78 |
addToken(2,Token.KEYWORD2); |
|
79 |
lastOffset += 2; |
|
80 |
i++; |
|
81 |
} |
|
82 |
} |
|
83 |
} |
|
84 |
break; |
|
85 |
case '"': |
|
86 |
if(backslash) |
|
87 |
backslash = false; |
|
88 |
else |
|
89 |
{ |
|
90 |
addToken(i - lastOffset,token); |
|
91 |
token = Token.LITERAL1; |
|
92 |
lastOffset = i; |
|
93 |
} |
|
94 |
break; |
|
95 |
case '\'': |
|
96 |
if(backslash) |
|
97 |
backslash = false; |
|
98 |
else |
|
99 |
{ |
|
100 |
addToken(i - lastOffset,token); |
|
101 |
token = Token.LITERAL2; |
|
102 |
lastOffset = i; |
|
103 |
} |
|
104 |
break; |
|
105 |
default: |
|
106 |
backslash = false; |
|
107 |
break; |
|
108 |
} |
|
109 |
case Token.KEYWORD2: |
|
110 |
backslash = false; |
|
111 |
if(c == ')' || c == '}') |
|
112 |
{ |
|
113 |
addToken(i1 - lastOffset,token); |
|
114 |
token = Token.NULL; |
|
115 |
lastOffset = i1; |
|
116 |
} |
|
117 |
break; |
|
118 |
case Token.LITERAL1: |
|
119 |
if(backslash) |
|
120 |
backslash = false; |
|
121 |
else if(c == '"') |
|
122 |
{ |
|
123 |
addToken(i1 - lastOffset,token); |
|
124 |
token = Token.NULL; |
|
125 |
lastOffset = i1; |
|
126 |
} |
|
127 |
else |
|
128 |
backslash = false; |
|
129 |
break; |
|
130 |
case Token.LITERAL2: |
|
131 |
if(backslash) |
|
132 |
backslash = false; |
|
133 |
else if(c == '\'') |
|
134 |
{ |
|
135 |
addToken(i1 - lastOffset,Token.LITERAL1); |
|
136 |
token = Token.NULL; |
|
137 |
lastOffset = i1; |
|
138 |
} |
|
139 |
else |
|
140 |
backslash = false; |
|
141 |
break; |
|
142 |
} |
|
143 |
} |
|
144 |
switch(token) |
|
145 |
{ |
|
146 |
case Token.KEYWORD2: |
|
147 |
addToken(length - lastOffset,Token.INVALID); |
|
148 |
token = Token.NULL; |
|
149 |
break; |
|
150 |
case Token.LITERAL2: |
|
151 |
addToken(length - lastOffset,Token.LITERAL1); |
|
152 |
break; |
|
153 |
default: |
|
154 |
addToken(length - lastOffset,token); |
|
155 |
break; |
|
156 |
} |
|
157 |
return token; |
|
158 |
} |
|
159 |
} |
|
0 | 160 |
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/TextUtilities.java | ||
---|---|---|
1 |
package com.iver.utiles.console.jedit; |
|
2 |
/* |
|
3 |
* TextUtilities.java - Utility functions used by the text area classes |
|
4 |
* Copyright (C) 1999 Slava Pestov |
|
5 |
* |
|
6 |
* You may use and modify this package for any purpose. Redistribution is |
|
7 |
* permitted, in both source and binary form, provided that this notice |
|
8 |
* remains intact in all source distributions of this package. |
|
9 |
*/ |
|
10 |
|
|
11 |
import javax.swing.text.*; |
|
12 |
|
|
13 |
/** |
|
14 |
* Class with several utility functions used by the text area component. |
|
15 |
* @author Slava Pestov |
|
16 |
* @version $Id$ |
|
17 |
*/ |
|
18 |
public class TextUtilities |
|
19 |
{ |
|
20 |
/** |
|
21 |
* Returns the offset of the bracket matching the one at the |
|
22 |
* specified offset of the document, or -1 if the bracket is |
|
23 |
* unmatched (or if the character is not a bracket). |
|
24 |
* @param doc The document |
|
25 |
* @param offset The offset |
|
26 |
* @exception BadLocationException If an out-of-bounds access |
|
27 |
* was attempted on the document text |
|
28 |
*/ |
|
29 |
public static int findMatchingBracket(Document doc, int offset) |
|
30 |
throws BadLocationException |
|
31 |
{ |
|
32 |
if(doc.getLength() == 0) |
|
33 |
return -1; |
|
34 |
char c = doc.getText(offset,1).charAt(0); |
|
35 |
char cprime; // c` - corresponding character |
|
36 |
boolean direction; // true = back, false = forward |
|
37 |
|
|
38 |
switch(c) |
|
39 |
{ |
|
40 |
case '(': cprime = ')'; direction = false; break; |
|
41 |
case ')': cprime = '('; direction = true; break; |
|
42 |
case '[': cprime = ']'; direction = false; break; |
|
43 |
case ']': cprime = '['; direction = true; break; |
|
44 |
case '{': cprime = '}'; direction = false; break; |
|
45 |
case '}': cprime = '{'; direction = true; break; |
|
46 |
default: return -1; |
|
47 |
} |
|
48 |
|
|
49 |
int count; |
|
50 |
|
|
51 |
// How to merge these two cases is left as an exercise |
|
52 |
// for the reader. |
|
53 |
|
|
54 |
// Go back or forward |
|
55 |
if(direction) |
|
56 |
{ |
|
57 |
// Count is 1 initially because we have already |
|
58 |
// `found' one closing bracket |
|
59 |
count = 1; |
|
60 |
|
|
61 |
// Get text[0,offset-1]; |
|
62 |
String text = doc.getText(0,offset); |
|
63 |
|
|
64 |
// Scan backwards |
|
65 |
for(int i = offset - 1; i >= 0; i--) |
|
66 |
{ |
|
67 |
// If text[i] == c, we have found another |
|
68 |
// closing bracket, therefore we will need |
|
69 |
// two opening brackets to complete the |
|
70 |
// match. |
|
71 |
char x = text.charAt(i); |
|
72 |
if(x == c) |
|
73 |
count++; |
|
74 |
|
|
75 |
// If text[i] == cprime, we have found a |
|
76 |
// opening bracket, so we return i if |
|
77 |
// --count == 0 |
|
78 |
else if(x == cprime) |
|
79 |
{ |
|
80 |
if(--count == 0) |
|
81 |
return i; |
|
82 |
} |
|
83 |
} |
|
84 |
} |
|
85 |
else |
|
86 |
{ |
|
87 |
// Count is 1 initially because we have already |
|
88 |
// `found' one opening bracket |
|
89 |
count = 1; |
|
90 |
|
|
91 |
// So we don't have to + 1 in every loop |
|
92 |
offset++; |
|
93 |
|
|
94 |
// Number of characters to check |
|
95 |
int len = doc.getLength() - offset; |
|
96 |
|
|
97 |
// Get text[offset+1,len]; |
|
98 |
String text = doc.getText(offset,len); |
|
99 |
|
|
100 |
// Scan forwards |
|
101 |
for(int i = 0; i < len; i++) |
|
102 |
{ |
|
103 |
// If text[i] == c, we have found another |
|
104 |
// opening bracket, therefore we will need |
|
105 |
// two closing brackets to complete the |
|
106 |
// match. |
|
107 |
char x = text.charAt(i); |
|
108 |
|
|
109 |
if(x == c) |
|
110 |
count++; |
|
111 |
|
|
112 |
// If text[i] == cprime, we have found an |
|
113 |
// closing bracket, so we return i if |
|
114 |
// --count == 0 |
|
115 |
else if(x == cprime) |
|
116 |
{ |
|
117 |
if(--count == 0) |
|
118 |
return i + offset; |
|
119 |
} |
|
120 |
} |
|
121 |
} |
|
122 |
|
|
123 |
// Nothing found |
|
124 |
return -1; |
|
125 |
} |
|
126 |
|
|
127 |
/** |
|
128 |
* Locates the start of the word at the specified position. |
|
129 |
* @param line The text |
|
130 |
* @param pos The position |
|
131 |
*/ |
|
132 |
public static int findWordStart(String line, int pos, String noWordSep) |
|
133 |
{ |
|
134 |
char ch = line.charAt(pos - 1); |
|
135 |
|
|
136 |
if(noWordSep == null) |
|
137 |
noWordSep = ""; |
|
138 |
boolean selectNoLetter = (!Character.isLetterOrDigit(ch) |
|
139 |
&& noWordSep.indexOf(ch) == -1); |
|
140 |
|
|
141 |
int wordStart = 0; |
|
142 |
for(int i = pos - 1; i >= 0; i--) |
|
143 |
{ |
|
144 |
ch = line.charAt(i); |
|
145 |
if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) && |
|
146 |
noWordSep.indexOf(ch) == -1)) |
|
147 |
{ |
|
148 |
wordStart = i + 1; |
|
149 |
break; |
|
150 |
} |
|
151 |
} |
|
152 |
|
|
153 |
return wordStart; |
|
154 |
} |
|
155 |
|
|
156 |
/** |
|
157 |
* Locates the end of the word at the specified position. |
|
158 |
* @param line The text |
|
159 |
* @param pos The position |
|
160 |
*/ |
|
161 |
public static int findWordEnd(String line, int pos, String noWordSep) |
|
162 |
{ |
|
163 |
char ch = line.charAt(pos); |
|
164 |
|
|
165 |
if(noWordSep == null) |
|
166 |
noWordSep = ""; |
|
167 |
boolean selectNoLetter = (!Character.isLetterOrDigit(ch) |
|
168 |
&& noWordSep.indexOf(ch) == -1); |
|
169 |
|
|
170 |
int wordEnd = line.length(); |
|
171 |
for(int i = pos; i < line.length(); i++) |
|
172 |
{ |
|
173 |
ch = line.charAt(i); |
|
174 |
if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) && |
|
175 |
noWordSep.indexOf(ch) == -1)) |
|
176 |
{ |
|
177 |
wordEnd = i; |
|
178 |
break; |
|
179 |
} |
|
180 |
} |
|
181 |
return wordEnd; |
|
182 |
} |
|
183 |
} |
|
0 | 184 |
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/Token.java | ||
---|---|---|
1 |
package com.iver.utiles.console.jedit; |
|
2 |
/* |
|
3 |
* Token.java - Generic token |
|
4 |
* Copyright (C) 1998, 1999 Slava Pestov |
|
5 |
* |
|
6 |
* You may use and modify this package for any purpose. Redistribution is |
|
7 |
* permitted, in both source and binary form, provided that this notice |
|
8 |
* remains intact in all source distributions of this package. |
|
9 |
*/ |
|
10 |
|
|
11 |
/** |
|
12 |
* A linked list of tokens. Each token has three fields - a token |
|
13 |
* identifier, which is a byte value that can be looked up in the |
|
14 |
* array returned by <code>SyntaxDocument.getColors()</code> |
|
15 |
* to get a color value, a length value which is the length of the |
|
16 |
* token in the text, and a pointer to the next token in the list. |
|
17 |
* |
|
18 |
* @author Slava Pestov |
|
19 |
* @version $Id$ |
|
20 |
*/ |
|
21 |
public class Token |
|
22 |
{ |
|
23 |
/** |
|
24 |
* Normal text token id. This should be used to mark |
|
25 |
* normal text. |
|
26 |
*/ |
|
27 |
public static final byte NULL = 0; |
|
28 |
|
|
29 |
/** |
|
30 |
* Comment 1 token id. This can be used to mark a comment. |
|
31 |
*/ |
|
32 |
public static final byte COMMENT1 = 1; |
|
33 |
|
|
34 |
/** |
|
35 |
* Comment 2 token id. This can be used to mark a comment. |
|
36 |
*/ |
|
37 |
public static final byte COMMENT2 = 2; |
|
38 |
|
|
39 |
|
|
40 |
/** |
|
41 |
* Literal 1 token id. This can be used to mark a string |
|
42 |
* literal (eg, C mode uses this to mark "..." literals) |
|
43 |
*/ |
|
44 |
public static final byte LITERAL1 = 3; |
|
45 |
|
|
46 |
/** |
|
47 |
* Literal 2 token id. This can be used to mark an object |
|
48 |
* literal (eg, Java mode uses this to mark true, false, etc) |
|
49 |
*/ |
|
50 |
public static final byte LITERAL2 = 4; |
|
51 |
|
|
52 |
/** |
|
53 |
* Label token id. This can be used to mark labels |
|
54 |
* (eg, C mode uses this to mark ...: sequences) |
|
55 |
*/ |
|
56 |
public static final byte LABEL = 5; |
|
57 |
|
|
58 |
/** |
|
59 |
* Keyword 1 token id. This can be used to mark a |
|
60 |
* keyword. This should be used for general language |
|
61 |
* constructs. |
|
62 |
*/ |
|
63 |
public static final byte KEYWORD1 = 6; |
|
64 |
|
|
65 |
/** |
|
66 |
* Keyword 2 token id. This can be used to mark a |
|
67 |
* keyword. This should be used for preprocessor |
|
68 |
* commands, or variables. |
|
69 |
*/ |
|
70 |
public static final byte KEYWORD2 = 7; |
|
71 |
|
|
72 |
/** |
|
73 |
* Keyword 3 token id. This can be used to mark a |
|
74 |
* keyword. This should be used for data types. |
|
75 |
*/ |
|
76 |
public static final byte KEYWORD3 = 8; |
|
77 |
|
|
78 |
/** |
|
79 |
* Operator token id. This can be used to mark an |
|
80 |
* operator. (eg, SQL mode marks +, -, etc with this |
|
81 |
* token type) |
|
82 |
*/ |
|
83 |
public static final byte OPERATOR = 9; |
|
84 |
|
|
85 |
/** |
|
86 |
* Invalid token id. This can be used to mark invalid |
|
87 |
* or incomplete tokens, so the user can easily spot |
|
88 |
* syntax errors. |
|
89 |
*/ |
|
90 |
public static final byte INVALID = 10; |
|
91 |
|
|
92 |
/** |
|
93 |
* The total number of defined token ids. |
|
94 |
*/ |
|
95 |
public static final byte ID_COUNT = 11; |
|
96 |
|
|
97 |
/** |
|
98 |
* The first id that can be used for internal state |
|
99 |
* in a token marker. |
|
100 |
*/ |
|
101 |
public static final byte INTERNAL_FIRST = 100; |
|
102 |
|
|
103 |
/** |
|
104 |
* The last id that can be used for internal state |
|
105 |
* in a token marker. |
|
106 |
*/ |
|
107 |
public static final byte INTERNAL_LAST = 126; |
|
108 |
|
|
109 |
/** |
|
110 |
* The token type, that along with a length of 0 |
|
111 |
* marks the end of the token list. |
|
112 |
*/ |
|
113 |
public static final byte END = 127; |
|
114 |
|
|
115 |
/** |
|
116 |
* The length of this token. |
|
117 |
*/ |
|
118 |
public int length; |
|
119 |
|
|
120 |
/** |
|
121 |
* The id of this token. |
|
122 |
*/ |
|
123 |
public byte id; |
|
124 |
|
|
125 |
/** |
|
126 |
* The next token in the linked list. |
|
127 |
*/ |
|
128 |
public Token next; |
|
129 |
|
|
130 |
/** |
|
131 |
* Creates a new token. |
|
132 |
* @param length The length of the token |
|
133 |
* @param id The id of the token |
|
134 |
*/ |
|
135 |
public Token(int length, byte id) |
|
136 |
{ |
|
137 |
this.length = length; |
|
138 |
this.id = id; |
|
139 |
} |
|
140 |
|
|
141 |
/** |
|
142 |
* Returns a string representation of this token. |
|
143 |
*/ |
|
144 |
public String toString() |
|
145 |
{ |
|
146 |
return "[id=" + id + ",length=" + length + "]"; |
|
147 |
} |
|
148 |
} |
|
0 | 149 |
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/TokenMarker.java | ||
---|---|---|
1 |
package com.iver.utiles.console.jedit; |
|
2 |
/* |
|
3 |
* TokenMarker.java - Generic token marker |
|
4 |
* Copyright (C) 1998, 1999 Slava Pestov |
|
5 |
* |
|
6 |
* You may use and modify this package for any purpose. Redistribution is |
|
7 |
* permitted, in both source and binary form, provided that this notice |
|
8 |
* remains intact in all source distributions of this package. |
|
9 |
*/ |
|
10 |
|
|
11 |
import javax.swing.text.Segment; |
|
12 |
import java.util.*; |
|
13 |
|
|
14 |
/** |
|
15 |
* A token marker that splits lines of text into tokens. Each token carries |
|
16 |
* a length field and an indentification tag that can be mapped to a color |
|
17 |
* for painting that token.<p> |
|
18 |
* |
|
19 |
* For performance reasons, the linked list of tokens is reused after each |
|
20 |
* line is tokenized. Therefore, the return value of <code>markTokens</code> |
|
21 |
* should only be used for immediate painting. Notably, it cannot be |
|
22 |
* cached. |
|
23 |
* |
|
24 |
* @author Slava Pestov |
|
25 |
* @version $Id$ |
|
26 |
* |
|
27 |
* @see org.gjt.sp.jedit.syntax.Token |
|
28 |
*/ |
|
29 |
public abstract class TokenMarker |
|
30 |
{ |
|
31 |
/** |
|
32 |
* A wrapper for the lower-level <code>markTokensImpl</code> method |
|
33 |
* that is called to split a line up into tokens. |
|
34 |
* @param line The line |
|
35 |
* @param lineIndex The line number |
|
36 |
*/ |
|
37 |
public Token markTokens(Segment line, int lineIndex) |
|
38 |
{ |
|
39 |
if(lineIndex >= length) |
|
40 |
{ |
|
41 |
throw new IllegalArgumentException("Tokenizing invalid line: " |
|
42 |
+ lineIndex); |
|
43 |
} |
|
44 |
|
|
45 |
lastToken = null; |
|
46 |
|
|
47 |
LineInfo info = lineInfo[lineIndex]; |
|
48 |
LineInfo prev; |
|
49 |
if(lineIndex == 0) |
|
50 |
prev = null; |
|
51 |
else |
|
52 |
prev = lineInfo[lineIndex - 1]; |
|
53 |
|
|
54 |
byte oldToken = info.token; |
|
55 |
byte token = markTokensImpl(prev == null ? |
|
56 |
Token.NULL : prev.token,line,lineIndex); |
|
57 |
|
|
58 |
info.token = token; |
|
59 |
|
|
60 |
/* |
|
61 |
* This is a foul hack. It stops nextLineRequested |
|
62 |
* from being cleared if the same line is marked twice. |
|
63 |
* |
|
64 |
* Why is this necessary? It's all JEditTextArea's fault. |
|
65 |
* When something is inserted into the text, firing a |
|
66 |
* document event, the insertUpdate() method shifts the |
|
67 |
* caret (if necessary) by the amount inserted. |
|
68 |
* |
|
69 |
* All caret movement is handled by the select() method, |
|
70 |
* which eventually pipes the new position to scrollTo() |
|
71 |
* and calls repaint(). |
|
72 |
* |
|
73 |
* Note that at this point in time, the new line hasn't |
|
74 |
* yet been painted; the caret is moved first. |
|
75 |
* |
|
76 |
* scrollTo() calls offsetToX(), which tokenizes the line |
|
77 |
* unless it is being called on the last line painted |
|
78 |
* (in which case it uses the text area's painter cached |
|
79 |
* token list). What scrollTo() does next is irrelevant. |
|
80 |
* |
|
81 |
* After scrollTo() has done it's job, repaint() is |
|
82 |
* called, and eventually we end up in paintLine(), whose |
|
83 |
* job is to paint the changed line. It, too, calls |
|
84 |
* markTokens(). |
|
85 |
* |
|
86 |
* The problem was that if the line started a multiline |
|
87 |
* token, the first markTokens() (done in offsetToX()) |
|
88 |
* would set nextLineRequested (because the line end |
|
89 |
* token had changed) but the second would clear it |
|
90 |
* (because the line was the same that time) and therefore |
|
91 |
* paintLine() would never know that it needed to repaint |
|
92 |
* subsequent lines. |
|
93 |
* |
|
94 |
* This bug took me ages to track down, that's why I wrote |
|
95 |
* all the relevant info down so that others wouldn't |
|
96 |
* duplicate it. |
|
97 |
*/ |
|
98 |
if(!(lastLine == lineIndex && nextLineRequested)) |
|
99 |
nextLineRequested = (oldToken != token); |
|
100 |
|
|
101 |
lastLine = lineIndex; |
|
102 |
|
|
103 |
addToken(0,Token.END); |
|
104 |
|
|
105 |
return firstToken; |
|
106 |
} |
|
107 |
|
|
108 |
/** |
|
109 |
* An abstract method that splits a line up into tokens. It |
|
110 |
* should parse the line, and call <code>addToken()</code> to |
|
111 |
* add syntax tokens to the token list. Then, it should return |
|
112 |
* the initial token type for the next line.<p> |
|
113 |
* |
|
114 |
* For example if the current line contains the start of a |
|
115 |
* multiline comment that doesn't end on that line, this method |
|
116 |
* should return the comment token type so that it continues on |
|
117 |
* the next line. |
|
118 |
* |
|
119 |
* @param token The initial token type for this line |
|
120 |
* @param line The line to be tokenized |
|
121 |
* @param lineIndex The index of the line in the document, |
|
122 |
* starting at 0 |
|
123 |
* @return The initial token type for the next line |
|
124 |
*/ |
|
125 |
protected abstract byte markTokensImpl(byte token, Segment line, |
|
126 |
int lineIndex); |
|
127 |
|
|
128 |
/** |
|
129 |
* Returns if the token marker supports tokens that span multiple |
|
130 |
* lines. If this is true, the object using this token marker is |
|
131 |
* required to pass all lines in the document to the |
|
132 |
* <code>markTokens()</code> method (in turn).<p> |
|
133 |
* |
|
134 |
* The default implementation returns true; it should be overridden |
|
135 |
* to return false on simpler token markers for increased speed. |
|
136 |
*/ |
|
137 |
public boolean supportsMultilineTokens() |
|
138 |
{ |
|
139 |
return true; |
|
140 |
} |
|
141 |
|
|
142 |
/** |
|
143 |
* Informs the token marker that lines have been inserted into |
|
144 |
* the document. This inserts a gap in the <code>lineInfo</code> |
|
145 |
* array. |
|
146 |
* @param index The first line number |
|
147 |
* @param lines The number of lines |
|
148 |
*/ |
|
149 |
public void insertLines(int index, int lines) |
|
150 |
{ |
|
151 |
if(lines <= 0) |
|
152 |
return; |
|
153 |
length += lines; |
|
154 |
ensureCapacity(length); |
|
155 |
int len = index + lines; |
|
156 |
System.arraycopy(lineInfo,index,lineInfo,len, |
|
157 |
lineInfo.length - len); |
|
158 |
|
|
159 |
for(int i = index + lines - 1; i >= index; i--) |
|
160 |
{ |
|
161 |
lineInfo[i] = new LineInfo(); |
|
162 |
} |
|
163 |
} |
|
164 |
|
|
165 |
/** |
|
166 |
* Informs the token marker that line have been deleted from |
|
167 |
* the document. This removes the lines in question from the |
|
168 |
* <code>lineInfo</code> array. |
|
169 |
* @param index The first line number |
|
170 |
* @param lines The number of lines |
|
171 |
*/ |
|
172 |
public void deleteLines(int index, int lines) |
|
173 |
{ |
|
174 |
if (lines <= 0) |
|
175 |
return; |
|
176 |
int len = index + lines; |
|
177 |
length -= lines; |
|
178 |
System.arraycopy(lineInfo,len,lineInfo, |
|
179 |
index,lineInfo.length - len); |
|
180 |
} |
|
181 |
|
|
182 |
/** |
|
183 |
* Returns the number of lines in this token marker. |
|
184 |
*/ |
|
185 |
public int getLineCount() |
|
186 |
{ |
|
187 |
return length; |
|
188 |
} |
|
189 |
|
|
190 |
/** |
|
191 |
* Returns true if the next line should be repainted. This |
|
192 |
* will return true after a line has been tokenized that starts |
|
193 |
* a multiline token that continues onto the next line. |
|
194 |
*/ |
|
195 |
public boolean isNextLineRequested() |
|
196 |
{ |
|
197 |
return nextLineRequested; |
|
198 |
} |
|
199 |
|
|
200 |
// protected members |
|
201 |
|
|
202 |
/** |
|
203 |
* The first token in the list. This should be used as the return |
|
204 |
* value from <code>markTokens()</code>. |
|
205 |
*/ |
|
206 |
protected Token firstToken; |
|
207 |
|
|
208 |
/** |
|
209 |
* The last token in the list. New tokens are added here. |
|
210 |
* This should be set to null before a new line is to be tokenized. |
|
211 |
*/ |
|
212 |
protected Token lastToken; |
|
213 |
|
|
214 |
/** |
|
215 |
* An array for storing information about lines. It is enlarged and |
|
216 |
* shrunk automatically by the <code>insertLines()</code> and |
|
217 |
* <code>deleteLines()</code> methods. |
|
218 |
*/ |
|
219 |
protected LineInfo[] lineInfo; |
|
220 |
|
|
221 |
/** |
|
222 |
* The number of lines in the model being tokenized. This can be |
|
223 |
* less than the length of the <code>lineInfo</code> array. |
|
224 |
*/ |
|
225 |
protected int length; |
|
226 |
|
|
227 |
/** |
|
228 |
* The last tokenized line. |
|
229 |
*/ |
|
230 |
protected int lastLine; |
|
231 |
|
|
232 |
/** |
|
233 |
* True if the next line should be painted. |
|
234 |
*/ |
|
235 |
protected boolean nextLineRequested; |
|
236 |
|
|
237 |
/** |
|
238 |
* Creates a new <code>TokenMarker</code>. This DOES NOT create |
|
239 |
* a lineInfo array; an initial call to <code>insertLines()</code> |
|
240 |
* does that. |
|
241 |
*/ |
|
242 |
protected TokenMarker() |
|
243 |
{ |
|
244 |
lastLine = -1; |
|
245 |
} |
|
246 |
|
|
247 |
/** |
|
248 |
* Ensures that the <code>lineInfo</code> array can contain the |
|
249 |
* specified index. This enlarges it if necessary. No action is |
|
250 |
* taken if the array is large enough already.<p> |
|
251 |
* |
|
252 |
* It should be unnecessary to call this under normal |
|
253 |
* circumstances; <code>insertLine()</code> should take care of |
|
254 |
* enlarging the line info array automatically. |
|
255 |
* |
|
256 |
* @param index The array index |
|
257 |
*/ |
|
258 |
protected void ensureCapacity(int index) |
|
259 |
{ |
|
260 |
if(lineInfo == null) |
|
261 |
lineInfo = new LineInfo[index + 1]; |
|
262 |
else if(lineInfo.length <= index) |
|
263 |
{ |
|
264 |
LineInfo[] lineInfoN = new LineInfo[(index + 1) * 2]; |
|
265 |
System.arraycopy(lineInfo,0,lineInfoN,0, |
|
266 |
lineInfo.length); |
|
267 |
lineInfo = lineInfoN; |
|
268 |
} |
|
269 |
} |
|
270 |
|
|
271 |
/** |
|
272 |
* Adds a token to the token list. |
|
273 |
* @param length The length of the token |
|
274 |
* @param id The id of the token |
|
275 |
*/ |
|
276 |
protected void addToken(int length, byte id) |
|
277 |
{ |
|
278 |
if(id >= Token.INTERNAL_FIRST && id <= Token.INTERNAL_LAST) |
|
279 |
throw new InternalError("Invalid id: " + id); |
|
280 |
|
|
281 |
if(length == 0 && id != Token.END) |
|
282 |
return; |
|
283 |
|
|
284 |
if(firstToken == null) |
|
285 |
{ |
|
286 |
firstToken = new Token(length,id); |
|
287 |
lastToken = firstToken; |
|
288 |
} |
|
289 |
else if(lastToken == null) |
|
290 |
{ |
|
291 |
lastToken = firstToken; |
|
292 |
firstToken.length = length; |
|
293 |
firstToken.id = id; |
|
294 |
} |
|
295 |
else if(lastToken.next == null) |
|
296 |
{ |
|
297 |
lastToken.next = new Token(length,id); |
|
298 |
lastToken = lastToken.next; |
|
299 |
} |
|
300 |
else |
|
301 |
{ |
|
302 |
lastToken = lastToken.next; |
|
303 |
lastToken.length = length; |
|
304 |
lastToken.id = id; |
|
305 |
} |
|
306 |
} |
|
307 |
|
|
308 |
/** |
|
309 |
* Inner class for storing information about tokenized lines. |
|
310 |
*/ |
|
311 |
public class LineInfo |
|
312 |
{ |
|
313 |
/** |
|
314 |
* Creates a new LineInfo object with token = Token.NULL |
|
315 |
* and obj = null. |
|
316 |
*/ |
|
317 |
public LineInfo() |
|
318 |
{ |
|
319 |
} |
|
320 |
|
|
321 |
/** |
|
322 |
* Creates a new LineInfo object with the specified |
|
323 |
* parameters. |
|
324 |
*/ |
|
325 |
public LineInfo(byte token, Object obj) |
|
326 |
{ |
|
327 |
this.token = token; |
|
328 |
this.obj = obj; |
|
329 |
} |
|
330 |
|
|
331 |
/** |
|
332 |
* The id of the last token of the line. |
|
333 |
*/ |
|
334 |
public byte token; |
|
335 |
|
|
336 |
/** |
|
337 |
* This is for use by the token marker implementations |
|
338 |
* themselves. It can be used to store anything that |
|
339 |
* is an object and that needs to exist on a per-line |
|
340 |
* basis. |
|
341 |
*/ |
|
342 |
public Object obj; |
|
343 |
} |
|
344 |
} |
|
0 | 345 |
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/SyntaxUtilities.java | ||
---|---|---|
1 |
package com.iver.utiles.console.jedit; |
|
2 |
/* |
|
3 |
* SyntaxUtilities.java - Utility functions used by syntax colorizing |
|
4 |
* Copyright (C) 1999 Slava Pestov |
|
5 |
* |
|
6 |
* You may use and modify this package for any purpose. Redistribution is |
|
7 |
* permitted, in both source and binary form, provided that this notice |
|
8 |
* remains intact in all source distributions of this package. |
|
9 |
*/ |
|
10 |
|
|
11 |
import javax.swing.text.*; |
|
12 |
import java.awt.*; |
|
13 |
|
|
14 |
/** |
|
15 |
* Class with several utility functions used by jEdit's syntax colorizing |
|
16 |
* subsystem. |
|
17 |
* |
|
18 |
* @author Slava Pestov |
|
19 |
* @version $Id$ |
|
20 |
*/ |
|
21 |
public class SyntaxUtilities |
|
22 |
{ |
|
23 |
/** |
|
24 |
* Checks if a subregion of a <code>Segment</code> is equal to a |
|
25 |
* string. |
|
26 |
* @param ignoreCase True if case should be ignored, false otherwise |
|
27 |
* @param text The segment |
|
28 |
* @param offset The offset into the segment |
|
29 |
* @param match The string to match |
|
30 |
*/ |
|
31 |
public static boolean regionMatches(boolean ignoreCase, Segment text, |
|
32 |
int offset, String match) |
|
33 |
{ |
|
34 |
int length = offset + match.length(); |
|
35 |
char[] textArray = text.array; |
|
36 |
if(length > text.offset + text.count) |
|
37 |
return false; |
|
38 |
for(int i = offset, j = 0; i < length; i++, j++) |
|
39 |
{ |
|
40 |
char c1 = textArray[i]; |
|
41 |
char c2 = match.charAt(j); |
|
42 |
if(ignoreCase) |
|
43 |
{ |
|
44 |
c1 = Character.toUpperCase(c1); |
|
45 |
c2 = Character.toUpperCase(c2); |
|
46 |
} |
|
47 |
if(c1 != c2) |
|
48 |
return false; |
|
49 |
} |
|
50 |
return true; |
|
51 |
} |
|
52 |
|
|
53 |
/** |
|
54 |
* Checks if a subregion of a <code>Segment</code> is equal to a |
|
55 |
* character array. |
|
56 |
* @param ignoreCase True if case should be ignored, false otherwise |
|
57 |
* @param text The segment |
|
58 |
* @param offset The offset into the segment |
|
59 |
* @param match The character array to match |
|
60 |
*/ |
|
61 |
public static boolean regionMatches(boolean ignoreCase, Segment text, |
|
62 |
int offset, char[] match) |
|
63 |
{ |
|
64 |
int length = offset + match.length; |
|
65 |
char[] textArray = text.array; |
|
66 |
if(length > text.offset + text.count) |
|
67 |
return false; |
|
68 |
for(int i = offset, j = 0; i < length; i++, j++) |
|
69 |
{ |
|
70 |
char c1 = textArray[i]; |
|
71 |
char c2 = match[j]; |
|
72 |
if(ignoreCase) |
|
73 |
{ |
|
74 |
c1 = Character.toUpperCase(c1); |
|
75 |
c2 = Character.toUpperCase(c2); |
|
76 |
} |
|
77 |
if(c1 != c2) |
|
78 |
return false; |
|
79 |
} |
|
80 |
return true; |
|
81 |
} |
|
82 |
|
|
83 |
/** |
|
84 |
* Returns the default style table. This can be passed to the |
|
85 |
* <code>setStyles()</code> method of <code>SyntaxDocument</code> |
|
86 |
* to use the default syntax styles. |
|
87 |
*/ |
|
88 |
public static SyntaxStyle[] getDefaultSyntaxStyles() |
|
89 |
{ |
|
90 |
SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT]; |
|
91 |
|
|
92 |
styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,false); |
|
93 |
styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,false); |
|
94 |
styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true); |
|
95 |
styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,false); |
|
96 |
styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false); |
|
97 |
styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false); |
|
98 |
styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true); |
|
99 |
styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true); |
|
100 |
styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true); |
|
101 |
styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true); |
|
102 |
|
|
103 |
return styles; |
|
104 |
} |
|
105 |
|
|
106 |
/** |
|
107 |
* Paints the specified line onto the graphics context. Note that this |
|
108 |
* method munges the offset and count values of the segment. |
|
109 |
* @param line The line segment |
|
110 |
* @param tokens The token list for the line |
|
111 |
* @param styles The syntax style list |
|
112 |
* @param expander The tab expander used to determine tab stops. May |
|
113 |
* be null |
|
114 |
* @param gfx The graphics context |
|
115 |
* @param x The x co-ordinate |
|
116 |
* @param y The y co-ordinate |
|
117 |
* @return The x co-ordinate, plus the width of the painted string |
|
118 |
*/ |
|
119 |
public static int paintSyntaxLine(Segment line, Token tokens, |
|
120 |
SyntaxStyle[] styles, TabExpander expander, Graphics gfx, |
|
121 |
int x, int y) |
|
122 |
{ |
|
123 |
Font defaultFont = gfx.getFont(); |
|
124 |
Color defaultColor = gfx.getColor(); |
|
125 |
|
|
126 |
int offset = 0; |
|
127 |
for(;;) |
|
128 |
{ |
|
129 |
byte id = tokens.id; |
|
130 |
if(id == Token.END) |
|
131 |
break; |
|
132 |
|
|
133 |
int length = tokens.length; |
|
134 |
if(id == Token.NULL) |
|
135 |
{ |
|
136 |
if(!defaultColor.equals(gfx.getColor())) |
|
137 |
gfx.setColor(defaultColor); |
|
138 |
if(!defaultFont.equals(gfx.getFont())) |
|
139 |
gfx.setFont(defaultFont); |
|
140 |
} |
|
141 |
else |
|
142 |
styles[id].setGraphicsFlags(gfx,defaultFont); |
|
143 |
|
|
144 |
line.count = length; |
|
145 |
x = Utilities.drawTabbedText(line,x,y,gfx,expander,0); |
|
146 |
line.offset += length; |
|
147 |
offset += length; |
|
148 |
|
|
149 |
tokens = tokens.next; |
|
150 |
} |
|
151 |
|
|
152 |
return x; |
|
153 |
} |
|
154 |
|
|
155 |
// private members |
|
156 |
private SyntaxUtilities() {} |
|
157 |
} |
|
0 | 158 |
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/KeywordMap.java | ||
---|---|---|
1 |
package com.iver.utiles.console.jedit; |
|
2 |
/* |
|
3 |
* KeywordMap.java - Fast keyword->id map |
|
4 |
* Copyright (C) 1998, 1999 Slava Pestov |
|
5 |
* Copyright (C) 1999 Mike Dillon |
|
6 |
* |
|
7 |
* You may use and modify this package for any purpose. Redistribution is |
|
8 |
* permitted, in both source and binary form, provided that this notice |
|
9 |
* remains intact in all source distributions of this package. |
|
10 |
*/ |
|
11 |
|
|
12 |
import javax.swing.text.Segment; |
|
13 |
|
|
14 |
/** |
|
15 |
* A <code>KeywordMap</code> is similar to a hashtable in that it maps keys |
|
16 |
* to values. However, the `keys' are Swing segments. This allows lookups of |
|
17 |
* text substrings without the overhead of creating a new string object. |
|
18 |
* <p> |
|
19 |
* This class is used by <code>CTokenMarker</code> to map keywords to ids. |
|
20 |
* |
|
21 |
* @author Slava Pestov, Mike Dillon |
|
22 |
* @version $Id$ |
|
23 |
*/ |
|
24 |
public class KeywordMap |
|
25 |
{ |
|
26 |
/** |
|
27 |
* Creates a new <code>KeywordMap</code>. |
|
28 |
* @param ignoreCase True if keys are case insensitive |
|
29 |
*/ |
|
30 |
public KeywordMap(boolean ignoreCase) |
|
31 |
{ |
|
32 |
this(ignoreCase, 52); |
|
33 |
this.ignoreCase = ignoreCase; |
|
34 |
} |
|
35 |
|
|
36 |
/** |
|
37 |
* Creates a new <code>KeywordMap</code>. |
|
38 |
* @param ignoreCase True if the keys are case insensitive |
|
39 |
* @param mapLength The number of `buckets' to create. |
|
40 |
* A value of 52 will give good performance for most maps. |
|
41 |
*/ |
|
42 |
public KeywordMap(boolean ignoreCase, int mapLength) |
|
43 |
{ |
|
44 |
this.mapLength = mapLength; |
|
45 |
this.ignoreCase = ignoreCase; |
|
46 |
map = new Keyword[mapLength]; |
|
47 |
} |
|
48 |
|
|
49 |
/** |
|
50 |
* Looks up a key. |
|
51 |
* @param text The text segment |
|
52 |
* @param offset The offset of the substring within the text segment |
|
53 |
* @param length The length of the substring |
|
54 |
*/ |
|
55 |
public byte lookup(Segment text, int offset, int length) |
|
56 |
{ |
|
57 |
if(length == 0) |
|
58 |
return Token.NULL; |
|
59 |
Keyword k = map[getSegmentMapKey(text, offset, length)]; |
|
60 |
while(k != null) |
|
61 |
{ |
|
62 |
if(length != k.keyword.length) |
|
63 |
{ |
|
64 |
k = k.next; |
|
65 |
continue; |
|
66 |
} |
|
67 |
if(SyntaxUtilities.regionMatches(ignoreCase,text,offset, |
|
68 |
k.keyword)) |
|
69 |
return k.id; |
|
70 |
k = k.next; |
|
71 |
} |
|
72 |
return Token.NULL; |
|
73 |
} |
|
74 |
|
|
75 |
/** |
|
76 |
* Adds a key-value mapping. |
|
77 |
* @param keyword The key |
|
78 |
* @Param id The value |
|
79 |
*/ |
|
80 |
public void add(String keyword, byte id) |
|
81 |
{ |
|
82 |
int key = getStringMapKey(keyword); |
|
83 |
map[key] = new Keyword(keyword.toCharArray(),id,map[key]); |
|
84 |
} |
|
85 |
|
|
86 |
/** |
|
87 |
* Returns true if the keyword map is set to be case insensitive, |
|
88 |
* false otherwise. |
|
89 |
*/ |
|
90 |
public boolean getIgnoreCase() |
|
91 |
{ |
|
92 |
return ignoreCase; |
|
93 |
} |
|
94 |
|
|
95 |
/** |
|
96 |
* Sets if the keyword map should be case insensitive. |
|
97 |
* @param ignoreCase True if the keyword map should be case |
|
98 |
* insensitive, false otherwise |
|
99 |
*/ |
|
100 |
public void setIgnoreCase(boolean ignoreCase) |
|
101 |
{ |
|
102 |
this.ignoreCase = ignoreCase; |
|
103 |
} |
|
104 |
|
|
105 |
// protected members |
|
106 |
protected int mapLength; |
|
107 |
|
|
108 |
protected int getStringMapKey(String s) |
|
109 |
{ |
|
110 |
return (Character.toUpperCase(s.charAt(0)) + |
|
111 |
Character.toUpperCase(s.charAt(s.length()-1))) |
|
112 |
% mapLength; |
|
113 |
} |
|
114 |
|
|
115 |
protected int getSegmentMapKey(Segment s, int off, int len) |
|
116 |
{ |
|
117 |
return (Character.toUpperCase(s.array[off]) + |
|
118 |
Character.toUpperCase(s.array[off + len - 1])) |
|
119 |
% mapLength; |
|
120 |
} |
|
121 |
|
|
122 |
// private members |
|
123 |
class Keyword |
|
124 |
{ |
|
125 |
public Keyword(char[] keyword, byte id, Keyword next) |
|
126 |
{ |
|
127 |
this.keyword = keyword; |
|
128 |
this.id = id; |
|
129 |
this.next = next; |
|
130 |
} |
|
131 |
|
|
132 |
public char[] keyword; |
|
133 |
public byte id; |
|
134 |
public Keyword next; |
|
135 |
} |
|
136 |
|
|
137 |
private Keyword[] map; |
|
138 |
private boolean ignoreCase; |
|
139 |
} |
|
0 | 140 |
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/PythonTokenMarker.java | ||
---|---|---|
1 |
package com.iver.utiles.console.jedit; |
|
2 |
/* |
|
3 |
* PythonTokenMarker.java - Python token marker |
|
4 |
* Copyright (C) 1999 Jonathan Revusky |
|
5 |
* Copyright (C) 1998, 1999 Slava Pestov |
|
6 |
* |
|
7 |
* You may use and modify this package for any purpose. Redistribution is |
|
8 |
* permitted, in both source and binary form, provided that this notice |
|
9 |
* remains intact in all source distributions of this package. |
|
10 |
*/ |
|
11 |
|
|
12 |
import javax.swing.text.Segment; |
|
13 |
|
|
14 |
/** |
|
15 |
* Python token marker. |
|
16 |
* |
|
17 |
* @author Jonathan Revusky |
|
18 |
* @version $Id$ |
|
19 |
*/ |
|
20 |
public class PythonTokenMarker extends TokenMarker |
|
21 |
{ |
|
22 |
private static final byte TRIPLEQUOTE1 = Token.INTERNAL_FIRST; |
|
23 |
private static final byte TRIPLEQUOTE2 = Token.INTERNAL_LAST; |
|
24 |
|
|
25 |
public PythonTokenMarker() |
|
26 |
{ |
|
27 |
this.keywords = getKeywords(); |
|
28 |
} |
|
29 |
|
|
30 |
public byte markTokensImpl(byte token, Segment line, int lineIndex) |
|
31 |
{ |
|
32 |
char[] array = line.array; |
|
33 |
int offset = line.offset; |
|
34 |
lastOffset = offset; |
|
35 |
lastKeyword = offset; |
|
36 |
int length = line.count + offset; |
|
37 |
boolean backslash = false; |
|
38 |
|
|
39 |
loop: for(int i = offset; i < length; i++) |
|
40 |
{ |
|
41 |
int i1 = (i+1); |
|
42 |
|
|
43 |
char c = array[i]; |
|
44 |
if(c == '\\') |
|
45 |
{ |
|
46 |
backslash = !backslash; |
|
47 |
continue; |
|
48 |
} |
|
49 |
|
|
50 |
switch(token) |
|
51 |
{ |
|
52 |
case Token.NULL: |
|
53 |
switch(c) |
|
54 |
{ |
|
55 |
case '#': |
|
56 |
if(backslash) |
|
57 |
backslash = false; |
|
58 |
else |
|
59 |
{ |
|
60 |
doKeyword(line,i,c); |
|
61 |
addToken(i - lastOffset,token); |
|
62 |
addToken(length - i,Token.COMMENT1); |
|
63 |
lastOffset = lastKeyword = length; |
|
64 |
break loop; |
|
65 |
} |
|
66 |
break; |
|
67 |
case '"': |
|
68 |
doKeyword(line,i,c); |
|
69 |
if(backslash) |
|
70 |
backslash = false; |
|
71 |
else |
|
72 |
{ |
|
73 |
addToken(i - lastOffset,token); |
|
74 |
if(SyntaxUtilities.regionMatches(false, |
|
75 |
line,i1,"\"\"")) |
|
76 |
{ |
|
77 |
token = TRIPLEQUOTE1; |
|
78 |
} |
|
79 |
else |
|
80 |
{ |
|
81 |
token = Token.LITERAL1; |
|
82 |
} |
|
83 |
lastOffset = lastKeyword = i; |
|
84 |
} |
|
85 |
break; |
|
86 |
case '\'': |
|
87 |
doKeyword(line,i,c); |
|
88 |
if(backslash) |
|
89 |
backslash = false; |
|
90 |
else |
|
91 |
{ |
|
92 |
addToken(i - lastOffset,token); |
|
93 |
if(SyntaxUtilities.regionMatches(false, |
|
94 |
line,i1,"''")) |
|
95 |
{ |
|
96 |
token = TRIPLEQUOTE2; |
|
97 |
} |
|
98 |
else |
|
99 |
{ |
|
100 |
token = Token.LITERAL2; |
|
101 |
} |
|
102 |
lastOffset = lastKeyword = i; |
|
103 |
} |
|
104 |
break; |
|
105 |
default: |
|
106 |
backslash = false; |
|
107 |
if(!Character.isLetterOrDigit(c) |
|
108 |
&& c != '_') |
|
109 |
doKeyword(line,i,c); |
|
110 |
break; |
|
111 |
} |
|
112 |
break; |
|
113 |
case Token.LITERAL1: |
|
114 |
if(backslash) |
|
115 |
backslash = false; |
|
116 |
else if(c == '"') |
|
117 |
{ |
|
118 |
addToken(i1 - lastOffset,token); |
|
119 |
token = Token.NULL; |
|
120 |
lastOffset = lastKeyword = i1; |
|
121 |
} |
|
122 |
break; |
|
123 |
case Token.LITERAL2: |
|
124 |
if(backslash) |
|
125 |
backslash = false; |
|
126 |
else if(c == '\'') |
|
127 |
{ |
|
128 |
addToken(i1 - lastOffset,Token.LITERAL1); |
|
129 |
token = Token.NULL; |
|
130 |
lastOffset = lastKeyword = i1; |
|
131 |
} |
|
132 |
break; |
|
133 |
case TRIPLEQUOTE1: |
|
134 |
if(backslash) |
|
135 |
backslash = false; |
|
136 |
else if(SyntaxUtilities.regionMatches(false, |
|
137 |
line,i,"\"\"\"")) |
|
138 |
{ |
|
139 |
addToken((i+=4) - lastOffset, |
|
140 |
Token.LITERAL1); |
|
141 |
token = Token.NULL; |
|
142 |
lastOffset = lastKeyword = i; |
|
143 |
} |
|
144 |
break; |
|
145 |
case TRIPLEQUOTE2: |
|
146 |
if(backslash) |
|
147 |
backslash = false; |
Also available in: Unified diff