001: /*
002: * HtmlFormatter.java
003: *
004: * Copyright (C) 1998-2002 Peter Graves
005: * $Id: HtmlFormatter.java,v 1.1.1.1 2002/09/24 16:08:29 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: public final class HtmlFormatter extends Formatter implements Constants {
025: // HTML formats must not overlap with Java formats!
026: private static final int HTML_FORMAT_FIRST = JavaFormatter.JAVA_FORMAT_LAST + 1;
027:
028: private static final int HTML_FORMAT_TEXT = HTML_FORMAT_FIRST;
029: private static final int HTML_FORMAT_COMMENT = HTML_FORMAT_FIRST + 1;
030: private static final int HTML_FORMAT_TAG = HTML_FORMAT_FIRST + 2;
031: private static final int HTML_FORMAT_TAG_IMAGE = HTML_FORMAT_FIRST + 3;
032: private static final int HTML_FORMAT_TAG_ANCHOR = HTML_FORMAT_FIRST + 4;
033: private static final int HTML_FORMAT_TAG_TABLE = HTML_FORMAT_FIRST + 5;
034: private static final int HTML_FORMAT_TAG_TABLE_ROW = HTML_FORMAT_FIRST + 6;
035: private static final int HTML_FORMAT_TAG_TABLE_DATA = HTML_FORMAT_FIRST + 7;
036: private static final int HTML_FORMAT_SCRIPT = HTML_FORMAT_FIRST + 8;
037:
038: private StringBuffer sb = new StringBuffer();
039:
040: private JavaFormatter javaFormatter;
041:
042: public HtmlFormatter(Buffer buffer) {
043: this .buffer = buffer;
044: javaFormatter = new JavaFormatter(buffer, LANGUAGE_JAVASCRIPT);
045: }
046:
047: private void endToken(int state) {
048: if (sb.length() > 0) {
049: int format = HTML_FORMAT_TEXT;
050: switch (state) {
051: case STATE_NEUTRAL:
052: break;
053: case STATE_TAG:
054: format = HTML_FORMAT_TAG;
055: break;
056: case STATE_HTML_COMMENT:
057: format = HTML_FORMAT_COMMENT;
058: break;
059: case STATE_SCRIPT:
060: format = HTML_FORMAT_SCRIPT;
061: break;
062: default:
063: break;
064: }
065: addSegment(sb.toString(), format);
066: sb.setLength(0);
067: }
068: }
069:
070: public LineSegmentList formatLine(Line line) {
071: if (line == null) {
072: clearSegmentList();
073: addSegment("", HTML_FORMAT_TEXT);
074: return segmentList;
075: }
076: final int flags = line.flags();
077: if (flags == STATE_SCRIPT || flags == STATE_COMMENT) {
078: final String trim = line.trim();
079: if (trim.startsWith("<!--")) {
080: clearSegmentList();
081: addSegment(line.getText(), HTML_FORMAT_COMMENT);
082: return segmentList;
083: }
084: if (!trim.regionMatches(true, 0, "</script>", 0, 9))
085: return javaFormatter.formatLine(line);
086: }
087: parseLine(line.getText(), flags);
088: for (int i = 0; i < segmentList.size(); i++) {
089: LineSegment segment = segmentList.getSegment(i);
090: if (segment.getFormat() != HTML_FORMAT_TAG)
091: continue;
092: String token = segment.getText().toLowerCase();
093: if (token.startsWith("<a ") || token.equals("<a>")
094: || token.equals("</a>"))
095: segment.setFormat(HTML_FORMAT_TAG_ANCHOR);
096: else if (token.startsWith("<img ") || token.equals("<img>"))
097: segment.setFormat(HTML_FORMAT_TAG_IMAGE);
098: else if (token.startsWith("<table ")
099: || token.equals("<table>")
100: || token.equals("</table>"))
101: segment.setFormat(HTML_FORMAT_TAG_TABLE);
102: else if (token.startsWith("<tr ") || token.equals("<tr>")
103: || token.equals("</tr>"))
104: segment.setFormat(HTML_FORMAT_TAG_TABLE_ROW);
105: else if (token.startsWith("<td ") || token.equals("<td>")
106: || token.equals("</td>"))
107: segment.setFormat(HTML_FORMAT_TAG_TABLE_DATA);
108: }
109: return segmentList;
110: }
111:
112: private void parseLine(String text, int state) {
113: if (Editor.tabsAreVisible())
114: text = Utilities
115: .makeTabsVisible(text, buffer.getTabWidth());
116: else
117: text = Utilities.detab(text, buffer.getTabWidth());
118: clearSegmentList();
119: sb.setLength(0);
120: int i = 0;
121: final int limit = text.length();
122: while (i < limit) {
123: char c = text.charAt(i);
124: if (state == STATE_HTML_COMMENT) {
125: if (i < limit - 2
126: && text.substring(i, i + 3).equals("-->")) {
127: sb.append("-->");
128: endToken(state);
129: state = STATE_NEUTRAL;
130: i += 3;
131: } else {
132: sb.append(c);
133: ++i;
134: }
135: continue;
136: }
137: if (state == STATE_TAG) {
138: if (c == '>') {
139: sb.append(c);
140: endToken(state);
141: state = STATE_NEUTRAL;
142: } else
143: sb.append(c);
144: ++i;
145: continue;
146: }
147: if (state == STATE_SCRIPT) {
148: if (c == '<') {
149: if (text.regionMatches(true, i, "</script>", 0, 4)) {
150: endToken(state);
151: state = STATE_TAG;
152: sb.append(text.substring(i, i + 9));
153: endToken(state);
154: state = STATE_NEUTRAL;
155: i += 9;
156: continue;
157: }
158: }
159: sb.append(c);
160: ++i;
161: continue;
162: }
163: if (state == STATE_SCRIPT_TAG) {
164: if (c == '>') {
165: sb.append(c);
166: endToken(state);
167: state = STATE_SCRIPT;
168: } else
169: sb.append(c);
170: ++i;
171: continue;
172: }
173: // Not in comment or tag.
174: if (c == '<') {
175: endToken(state);
176: if (text.regionMatches(i, "<!--", 0, 4)) {
177: state = STATE_HTML_COMMENT;
178: sb.append("<!--");
179: i += 4;
180: continue;
181: }
182: sb.append(c);
183: state = STATE_TAG;
184: } else
185: sb.append(c);
186: ++i;
187: }
188: endToken(state);
189: }
190:
191: public boolean parseBuffer() {
192: Line line = buffer.getFirstLine();
193: if (line == null)
194: return false;
195: Position pos = new Position(line, 0);
196: boolean changed = false;
197: int state = STATE_NEUTRAL;
198: while (line != null) {
199: int oldflags = line.flags();
200: if (state != oldflags) {
201: line.setFlags(state);
202: changed = true;
203: }
204: final int limit = line.length();
205: for (int i = 0; i < limit; i++) {
206: char c = line.charAt(i);
207: if (state == STATE_HTML_COMMENT) {
208: if (c == '-') {
209: pos.moveTo(line, i);
210: if (pos.lookingAt("-->")) {
211: state = STATE_NEUTRAL;
212: i += 2;
213: continue;
214: }
215: }
216: continue;
217: }
218: if (state == STATE_SCRIPT_TAG) {
219: if (c == '>') {
220: state = STATE_SCRIPT;
221: continue;
222: }
223: }
224: if (state == STATE_TAG) {
225: if (c == '>') {
226: state = STATE_NEUTRAL;
227: continue;
228: }
229: }
230: if (state == STATE_SCRIPT) {
231: if (c == '<') {
232: pos.moveTo(line, i);
233: if (pos.lookingAtIgnoreCase("</script>")) {
234: state = STATE_NEUTRAL;
235: i += 8;
236: }
237: } else if (c == '/' && i < limit - 1) {
238: c = line.charAt(i + 1);
239: if (c == '*') {
240: pos.moveTo(line, i);
241: state = STATE_COMMENT;
242: ++i;
243: }
244: }
245: continue;
246: }
247: if (state == STATE_COMMENT) {
248: if (c == '*' && i < limit - 1) {
249: c = line.charAt(i + 1);
250: if (c == '/') {
251: pos.moveTo(line, i);
252: state = STATE_SCRIPT;
253: ++i;
254: }
255: }
256: continue;
257: }
258: // Neutral state.
259: if (c == '<') {
260: pos.moveTo(line, i);
261: if (pos.lookingAt("<!--")) {
262: state = STATE_HTML_COMMENT;
263: i += 3;
264: continue;
265: }
266: if (pos.lookingAtIgnoreCase("<script>")) {
267: state = STATE_SCRIPT;
268: i += 7;
269: continue;
270: }
271: if (pos.lookingAtIgnoreCase("<script ")) {
272: state = STATE_SCRIPT_TAG;
273: i += 7;
274: continue;
275: }
276: state = STATE_TAG;
277: continue;
278: }
279: }
280: line = line.next();
281: }
282: buffer.setNeedsParsing(false);
283: return changed;
284: }
285:
286: public FormatTable getFormatTable() {
287: if (formatTable == null) {
288: formatTable = javaFormatter.getFormatTable();
289: formatTable.setModeName("HtmlMode");
290: formatTable.addEntryFromPrefs(HTML_FORMAT_TEXT, "text");
291: formatTable.addEntryFromPrefs(HTML_FORMAT_COMMENT,
292: "comment");
293: formatTable.addEntryFromPrefs(HTML_FORMAT_TAG, "tag");
294: formatTable.addEntryFromPrefs(HTML_FORMAT_TAG_IMAGE,
295: "image");
296: formatTable.addEntryFromPrefs(HTML_FORMAT_TAG_ANCHOR,
297: "anchor");
298: formatTable.addEntryFromPrefs(HTML_FORMAT_TAG_TABLE,
299: "table");
300: formatTable.addEntryFromPrefs(HTML_FORMAT_TAG_TABLE_ROW,
301: "tableRow");
302: formatTable.addEntryFromPrefs(HTML_FORMAT_TAG_TABLE_DATA,
303: "tableData");
304: formatTable.addEntryFromPrefs(HTML_FORMAT_SCRIPT, "script");
305: }
306: return formatTable;
307: }
308:
309: public void reset() {
310: javaFormatter.reset();
311: super.reset();
312: }
313: }
|