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 }