View Javadoc

1   /*
2    * HTMLTokenMarker.java - HTML token marker
3    * Copyright (C) 1998, 1999 Slava Pestov
4    *
5    * You may use and modify this package for any purpose. Redistribution is
6    * permitted, in both source and binary form, provided that this notice
7    * remains intact in all source distributions of this package.
8    */
9   
10  package org.syntax.jedit.tokenmarker;
11  
12  import javax.swing.text.Segment;
13  
14  import org.syntax.jedit.KeywordMap;
15  import org.syntax.jedit.SyntaxUtilities;
16  
17  /***
18   * HTML token marker.
19   *
20   * @author Slava Pestov
21   * @version $Id: HTMLTokenMarker.java,v 1.34 1999/12/13 03:40:29 sp Exp $
22   */
23  public class HTMLTokenMarker extends TokenMarker
24  {
25  	public static final byte JAVASCRIPT = Token.INTERNAL_FIRST;
26  
27  	public HTMLTokenMarker()
28  	{
29  		this(true);
30  	}
31  
32  	public HTMLTokenMarker(boolean js)
33  	{
34  		this.js = js;
35  		keywords = JavaScriptTokenMarker.getKeywords();
36  	}
37  
38  	public byte markTokensImpl(byte token, Segment line, int lineIndex)
39  	{
40  		char[] array = line.array;
41  		int offset = line.offset;
42  		lastOffset = offset;
43  		lastKeyword = offset;
44  		int length = line.count + offset;
45  		boolean backslash = false;
46  
47  loop:		for(int i = offset; i < length; i++)
48  		{
49  			int i1 = (i+1);
50  
51  			char c = array[i];
52  			if(c == '//')
53  			{
54  				backslash = !backslash;
55  				continue;
56  			}
57  
58  			switch(token)
59  			{
60  			case Token.NULL: // HTML text
61  				backslash = false;
62  				switch(c)
63  				{
64  				case '<':
65  					addToken(i - lastOffset,token);
66  					lastOffset = lastKeyword = i;
67  					if(SyntaxUtilities.regionMatches(false,
68  						line,i1,"!--"))
69  					{
70  						i += 3;
71  						token = Token.COMMENT1;
72  					}
73  					else if(js && SyntaxUtilities.regionMatches(
74  						true,line,i1,"script>"))
75  					{
76  						addToken(8,Token.KEYWORD1);
77  						lastOffset = lastKeyword = (i += 8);
78  						token = JAVASCRIPT;
79  					}
80  					else
81  					{
82  						token = Token.KEYWORD1;
83  					}
84  					break;
85  				case '&':
86  					addToken(i - lastOffset,token);
87  					lastOffset = lastKeyword = i;
88  					token = Token.KEYWORD2;
89  					break;
90  				}
91  				break;
92  			case Token.KEYWORD1: // Inside a tag
93  				backslash = false;
94  				if(c == '>')
95  				{
96  					addToken(i1 - lastOffset,token);
97  					lastOffset = lastKeyword = i1;
98  					token = Token.NULL;
99  				}
100 				break;
101 			case Token.KEYWORD2: // Inside an entity
102 				backslash = false;
103 				if(c == ';')
104 				{
105 					addToken(i1 - lastOffset,token);
106 					lastOffset = lastKeyword = i1;
107 					token = Token.NULL;
108 					break;
109 				}
110 				break;
111 			case Token.COMMENT1: // Inside a comment
112 				backslash = false;
113 				if(SyntaxUtilities.regionMatches(false,line,i,"-->"))
114 				{
115 					addToken((i + 3) - lastOffset,token);
116 					lastOffset = lastKeyword = i + 3;
117 					token = Token.NULL;
118 				}
119 				break;
120 			case JAVASCRIPT: // Inside a JavaScript
121 				switch(c)
122 				{
123 				case '<':
124 					backslash = false;
125 					doKeyword(line,i,c);
126 					if(SyntaxUtilities.regionMatches(true,
127 						line,i1,"/script>"))
128 					{
129 						addToken(i - lastOffset,
130 							Token.NULL);
131 						addToken(9,Token.KEYWORD1);
132 						lastOffset = lastKeyword = (i += 9);
133 						token = Token.NULL;
134 					}
135 					break;
136 				case '"':
137 					if(backslash)
138 						backslash = false;
139 					else
140 					{
141 						doKeyword(line,i,c);
142 						addToken(i - lastOffset,Token.NULL);
143 						lastOffset = lastKeyword = i;
144 						token = Token.LITERAL1;
145 					}
146 					break;
147 				case '\'':
148 					if(backslash)
149 						backslash = false;
150 					else
151 					{
152 						doKeyword(line,i,c);
153 						addToken(i - lastOffset,Token.NULL);
154 						lastOffset = lastKeyword = i;
155 						token = Token.LITERAL2;
156 					}
157 					break;
158 				case '/':
159 					backslash = false;
160 					doKeyword(line,i,c);
161 					if(length - i > 1)
162 					{
163 						addToken(i - lastOffset,Token.NULL);
164 						lastOffset = lastKeyword = i;
165 						if(array[i1] == '/')
166 						{
167 							addToken(length - i,Token.COMMENT2);
168 							lastOffset = lastKeyword = length;
169 							break loop;
170 						}
171 						else if(array[i1] == '*')
172 						{
173 							token = Token.COMMENT2;
174 						}
175 					}
176 					break;
177 				default:					backslash = false;
178 					if(!Character.isLetterOrDigit(c)
179 						&& c != '_')
180 						doKeyword(line,i,c);
181 					break;
182 				}
183 				break;
184 			case Token.LITERAL1: // JavaScript "..."
185 				if(backslash)
186 					backslash = false;
187 				else if(c == '"')
188 				{
189 					addToken(i1 - lastOffset,Token.LITERAL1);
190 					lastOffset = lastKeyword = i1;
191 					token = JAVASCRIPT;
192 				}
193 				break;
194 			case Token.LITERAL2: // JavaScript '...'
195 				if(backslash)
196 					backslash = false;
197 				else if(c == '\'')
198 				{
199 					addToken(i1 - lastOffset,Token.LITERAL1);
200 					lastOffset = lastKeyword = i1;
201 					token = JAVASCRIPT;
202 				}
203 				break;
204 			case Token.COMMENT2: // Inside a JavaScript comment
205 				backslash = false;
206 				if(c == '*' && length - i > 1 && array[i1] == '/')
207 				{
208 					addToken((i+=2) - lastOffset,Token.COMMENT2);
209 					lastOffset = lastKeyword = i;
210 					token = JAVASCRIPT;
211 				}
212 				break;
213 			default:
214 				throw new InternalError("Invalid state: "
215 					+ token);
216 			}
217 		}
218 
219 		switch(token)
220 		{
221 		case Token.LITERAL1:
222 		case Token.LITERAL2:
223 			addToken(length - lastOffset,Token.INVALID);
224 			token = JAVASCRIPT;
225 			break;
226 		case Token.KEYWORD2:
227 			addToken(length - lastOffset,Token.INVALID);
228 			token = Token.NULL;
229 			break;
230 		case JAVASCRIPT:
231 			doKeyword(line,length,'\0');
232 			addToken(length - lastOffset,Token.NULL);
233 			break;
234 		default:
235 			addToken(length - lastOffset,token);
236 			break;
237 		}
238 
239 		return token;
240 	}
241 
242 	// private members
243 	private KeywordMap keywords;
244 	private boolean js;
245 	private int lastOffset;
246 	private int lastKeyword;
247 
248 	private boolean doKeyword(Segment line, int i, char c)
249 	{
250 		int i1 = i+1;
251 
252 		int len = i - lastKeyword;
253 		byte id = keywords.lookup(line,lastKeyword,len);
254 		if(id != Token.NULL)
255 		{
256 			if(lastKeyword != lastOffset)
257 				addToken(lastKeyword - lastOffset,Token.NULL);
258 			addToken(len,id);
259 			lastOffset = i;
260 		}
261 		lastKeyword = i1;
262 		return false;
263 	}
264 }