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, line, i1, "!--" ) )
68  					{
69  						i += 3;
70  						token = Token.COMMENT1;
71  					}
72  					else if( js && SyntaxUtilities.regionMatches( true, line, i1, "script>" ) )
73  					{
74  						addToken( 8, Token.KEYWORD1 );
75  						lastOffset = lastKeyword = ( i += 8 );
76  						token = JAVASCRIPT;
77  					}
78  					else
79  					{
80  						token = Token.KEYWORD1;
81  					}
82  					break;
83  				case '&' :
84  					addToken( i - lastOffset, token );
85  					lastOffset = lastKeyword = i;
86  					token = Token.KEYWORD2;
87  					break;
88  				}
89  				break;
90  			case Token.KEYWORD1 : // Inside a tag
91  				backslash = false;
92  				if( c == '>' )
93  				{
94  					addToken( i1 - lastOffset, token );
95  					lastOffset = lastKeyword = i1;
96  					token = Token.NULL;
97  				}
98  				break;
99  			case Token.KEYWORD2 : // Inside an entity
100 				backslash = false;
101 				if( c == ';' )
102 				{
103 					addToken( i1 - lastOffset, token );
104 					lastOffset = lastKeyword = i1;
105 					token = Token.NULL;
106 					break;
107 				}
108 				break;
109 			case Token.COMMENT1 : // Inside a comment
110 				backslash = false;
111 				if( SyntaxUtilities.regionMatches( false, line, i, "-->" ) )
112 				{
113 					addToken( ( i + 3 ) - lastOffset, token );
114 					lastOffset = lastKeyword = i + 3;
115 					token = Token.NULL;
116 				}
117 				break;
118 			case JAVASCRIPT : // Inside a JavaScript
119 				switch( c )
120 				{
121 				case '<' :
122 					backslash = false;
123 					doKeyword( line, i, c );
124 					if( SyntaxUtilities.regionMatches( true, line, i1, "/script>" ) )
125 					{
126 						addToken( i - lastOffset, Token.NULL );
127 						addToken( 9, Token.KEYWORD1 );
128 						lastOffset = lastKeyword = ( i += 9 );
129 						token = Token.NULL;
130 					}
131 					break;
132 				case '"' :
133 					if( backslash )
134 						backslash = false;
135 					else
136 					{
137 						doKeyword( line, i, c );
138 						addToken( i - lastOffset, Token.NULL );
139 						lastOffset = lastKeyword = i;
140 						token = Token.LITERAL1;
141 					}
142 					break;
143 				case '\'' :
144 					if( backslash )
145 						backslash = false;
146 					else
147 					{
148 						doKeyword( line, i, c );
149 						addToken( i - lastOffset, Token.NULL );
150 						lastOffset = lastKeyword = i;
151 						token = Token.LITERAL2;
152 					}
153 					break;
154 				case '/' :
155 					backslash = false;
156 					doKeyword( line, i, c );
157 					if( length - i > 1 )
158 					{
159 						addToken( i - lastOffset, Token.NULL );
160 						lastOffset = lastKeyword = i;
161 						if( array[i1] == '/' )
162 						{
163 							addToken( length - i, Token.COMMENT2 );
164 							lastOffset = lastKeyword = length;
165 							break loop;
166 						}
167 						else if( array[i1] == '*' )
168 						{
169 							token = Token.COMMENT2;
170 						}
171 					}
172 					break;
173 				default :
174 					backslash = false;
175 					if( !Character.isLetterOrDigit( c ) && c != '_' )
176 						doKeyword( line, i, c );
177 					break;
178 				}
179 				break;
180 			case Token.LITERAL1 : // JavaScript "..."
181 				if( backslash )
182 					backslash = false;
183 				else if( c == '"' )
184 				{
185 					addToken( i1 - lastOffset, Token.LITERAL1 );
186 					lastOffset = lastKeyword = i1;
187 					token = JAVASCRIPT;
188 				}
189 				break;
190 			case Token.LITERAL2 : // JavaScript '...'
191 				if( backslash )
192 					backslash = false;
193 				else if( c == '\'' )
194 				{
195 					addToken( i1 - lastOffset, Token.LITERAL1 );
196 					lastOffset = lastKeyword = i1;
197 					token = JAVASCRIPT;
198 				}
199 				break;
200 			case Token.COMMENT2 : // Inside a JavaScript comment
201 				backslash = false;
202 				if( c == '*' && length - i > 1 && array[i1] == '/' )
203 				{
204 					addToken( ( i += 2 ) - lastOffset, Token.COMMENT2 );
205 					lastOffset = lastKeyword = i;
206 					token = JAVASCRIPT;
207 				}
208 				break;
209 			default :
210 				throw new InternalError( "Invalid state: " + token );
211 			}
212 		}
213 
214 		switch( token )
215 		{
216 		case Token.LITERAL1 :
217 		case Token.LITERAL2 :
218 			addToken( length - lastOffset, Token.INVALID );
219 			token = JAVASCRIPT;
220 			break;
221 		case Token.KEYWORD2 :
222 			addToken( length - lastOffset, Token.INVALID );
223 			token = Token.NULL;
224 			break;
225 		case JAVASCRIPT :
226 			doKeyword( line, length, '\0' );
227 			addToken( length - lastOffset, Token.NULL );
228 			break;
229 		default :
230 			addToken( length - lastOffset, token );
231 			break;
232 		}
233 
234 		return token;
235 	}
236 
237 	// private members
238 	private KeywordMap keywords;
239 	private boolean js;
240 	private int lastOffset;
241 	private int lastKeyword;
242 
243 	private boolean doKeyword( Segment line, int i, char c )
244 	{
245 		int i1 = i + 1;
246 
247 		int len = i - lastKeyword;
248 		byte id = keywords.lookup( line, lastKeyword, len );
249 		if( id != Token.NULL )
250 		{
251 			if( lastKeyword != lastOffset )
252 				addToken( lastKeyword - lastOffset, Token.NULL );
253 			addToken( len, id );
254 			lastOffset = i;
255 		}
256 		lastKeyword = i1;
257 		return false;
258 	}
259 }