001: /*
002: * Copyright (C) 2005 - 2008 JasperSoft Corporation. All rights reserved.
003: * http://www.jaspersoft.com.
004: *
005: * Unless you have purchased a commercial license agreement from JasperSoft,
006: * the following license terms apply:
007: *
008: * This program is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU General Public License version 2 as published by
010: * the Free Software Foundation.
011: *
012: * This program is distributed WITHOUT ANY WARRANTY; and without the
013: * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
014: * See the GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, see http://www.gnu.org/licenses/gpl.txt
018: * or write to:
019: *
020: * Free Software Foundation, Inc.,
021: * 59 Temple Place - Suite 330,
022: * Boston, MA USA 02111-1307
023: *
024: *
025: *
026: *
027: * HTMLTokenMarker.java
028: *
029: */
030:
031: package org.syntax.jedit.tokenmarker;
032:
033: import org.syntax.jedit.*;
034: import javax.swing.text.Segment;
035:
036: /**
037: * HTML token marker.
038: *
039: * @author Slava Pestov
040: * @version $Id: HTMLTokenMarker.java 1167 2008-01-15 18:49:05Z gtoffoli $
041: */
042: public class HTMLTokenMarker extends TokenMarker {
043: public static final byte JAVASCRIPT = Token.INTERNAL_FIRST;
044:
045: public HTMLTokenMarker() {
046: this (true);
047: }
048:
049: public HTMLTokenMarker(boolean js) {
050: this .js = js;
051: keywords = JavaScriptTokenMarker.getKeywords();
052: }
053:
054: public byte markTokensImpl(byte token, Segment line, int lineIndex) {
055: char[] array = line.array;
056: int offset = line.offset;
057: lastOffset = offset;
058: lastKeyword = offset;
059: int length = line.count + offset;
060: boolean backslash = false;
061:
062: loop: for (int i = offset; i < length; i++) {
063: int i1 = (i + 1);
064:
065: char c = array[i];
066: if (c == '\\') {
067: backslash = !backslash;
068: continue;
069: }
070:
071: switch (token) {
072: case Token.NULL: // HTML text
073: backslash = false;
074: switch (c) {
075: case '<':
076: addToken(i - lastOffset, token);
077: lastOffset = lastKeyword = i;
078: if (SyntaxUtilities.regionMatches(false, line, i1,
079: "!--")) {
080: i += 3;
081: token = Token.COMMENT1;
082: } else if (js
083: && SyntaxUtilities.regionMatches(true,
084: line, i1, "script>")) {
085: addToken(8, Token.KEYWORD1);
086: lastOffset = lastKeyword = (i += 8);
087: token = JAVASCRIPT;
088: } else {
089: token = Token.KEYWORD1;
090: }
091: break;
092: case '&':
093: addToken(i - lastOffset, token);
094: lastOffset = lastKeyword = i;
095: token = Token.KEYWORD2;
096: break;
097: }
098: break;
099: case Token.KEYWORD1: // Inside a tag
100: backslash = false;
101: if (c == '>') {
102: addToken(i1 - lastOffset, token);
103: lastOffset = lastKeyword = i1;
104: token = Token.NULL;
105: }
106: break;
107: case Token.KEYWORD2: // Inside an entity
108: backslash = false;
109: if (c == ';') {
110: addToken(i1 - lastOffset, token);
111: lastOffset = lastKeyword = i1;
112: token = Token.NULL;
113: break;
114: }
115: break;
116: case Token.COMMENT1: // Inside a comment
117: backslash = false;
118: if (SyntaxUtilities
119: .regionMatches(false, line, i, "-->")) {
120: addToken((i + 3) - lastOffset, token);
121: lastOffset = lastKeyword = i + 3;
122: token = Token.NULL;
123: }
124: break;
125: case JAVASCRIPT: // Inside a JavaScript
126: switch (c) {
127: case '<':
128: backslash = false;
129: doKeyword(line, i, c);
130: if (SyntaxUtilities.regionMatches(true, line, i1,
131: "/script>")) {
132: addToken(i - lastOffset, Token.NULL);
133: addToken(9, Token.KEYWORD1);
134: lastOffset = lastKeyword = (i += 9);
135: token = Token.NULL;
136: }
137: break;
138: case '"':
139: if (backslash)
140: backslash = false;
141: else {
142: doKeyword(line, i, c);
143: addToken(i - lastOffset, Token.NULL);
144: lastOffset = lastKeyword = i;
145: token = Token.LITERAL1;
146: }
147: break;
148: case '\'':
149: if (backslash)
150: backslash = false;
151: else {
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: addToken(i - lastOffset, Token.NULL);
163: lastOffset = lastKeyword = i;
164: if (array[i1] == '/') {
165: addToken(length - i, Token.COMMENT2);
166: lastOffset = lastKeyword = length;
167: break loop;
168: } else if (array[i1] == '*') {
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: addToken(i1 - lastOffset, Token.LITERAL1);
185: lastOffset = lastKeyword = i1;
186: token = JAVASCRIPT;
187: }
188: break;
189: case Token.LITERAL2: // JavaScript '...'
190: if (backslash)
191: backslash = false;
192: else if (c == '\'') {
193: addToken(i1 - lastOffset, Token.LITERAL1);
194: lastOffset = lastKeyword = i1;
195: token = JAVASCRIPT;
196: }
197: break;
198: case Token.COMMENT2: // Inside a JavaScript comment
199: backslash = false;
200: if (c == '*' && length - i > 1 && array[i1] == '/') {
201: addToken((i += 2) - lastOffset, Token.COMMENT2);
202: lastOffset = lastKeyword = i;
203: token = JAVASCRIPT;
204: }
205: break;
206: default:
207: throw new InternalError("Invalid state: " + token);
208: }
209: }
210:
211: switch (token) {
212: case Token.LITERAL1:
213: case Token.LITERAL2:
214: addToken(length - lastOffset, Token.INVALID);
215: token = JAVASCRIPT;
216: break;
217: case Token.KEYWORD2:
218: addToken(length - lastOffset, Token.INVALID);
219: token = Token.NULL;
220: break;
221: case JAVASCRIPT:
222: doKeyword(line, length, '\0');
223: addToken(length - lastOffset, Token.NULL);
224: break;
225: default:
226: addToken(length - lastOffset, token);
227: break;
228: }
229:
230: return token;
231: }
232:
233: // private members
234: private KeywordMap keywords;
235: private boolean js;
236: private int lastOffset;
237: private int lastKeyword;
238:
239: private boolean doKeyword(Segment line, int i, char c) {
240: int i1 = i + 1;
241:
242: int len = i - lastKeyword;
243: byte id = keywords.lookup(line, lastKeyword, len);
244: if (id != Token.NULL) {
245: if (lastKeyword != lastOffset)
246: addToken(lastKeyword - lastOffset, Token.NULL);
247: addToken(len, id);
248: lastOffset = i;
249: }
250: lastKeyword = i1;
251: return false;
252: }
253: }
|