2 * Copyright (c) 2002-2004 Widespace, OU and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * Igor Malinin - initial contribution
11 * $Id: XMLPartitionScanner.java,v 1.5 2006-10-21 23:14:13 pombredanne Exp $
14 package net.sourceforge.phpeclipse.xml.ui.internal.text;
16 import java.util.HashMap;
19 import org.eclipse.jface.text.Assert;
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.rules.ICharacterScanner;
23 import org.eclipse.jface.text.rules.IPartitionTokenScanner;
24 import org.eclipse.jface.text.rules.IToken;
25 import org.eclipse.jface.text.rules.Token;
30 * @author Igor Malinin
32 public class XMLPartitionScanner implements IPartitionTokenScanner {
33 public static final String XML_PI = "__xml_processing_instruction";
35 public static final String XML_COMMENT = "__xml_comment";
37 public static final String XML_DECL = "__xml_declaration";
39 public static final String XML_TAG = "__xml_tag";
41 public static final String XML_ATTRIBUTE = "__xml_attribute";
43 public static final String XML_CDATA = "__xml_cdata";
45 public static final String DTD_INTERNAL = "__dtd_internal";
47 public static final String DTD_INTERNAL_PI = "__dtd_internal_pi";
49 public static final String DTD_INTERNAL_COMMENT = "__dtd_internal_comment";
51 public static final String DTD_INTERNAL_DECL = "__dtd_internal_declaration";
53 public static final String DTD_CONDITIONAL = "__dtd_conditional";
55 public static final int STATE_DEFAULT = 0;
57 public static final int STATE_TAG = 1;
59 public static final int STATE_DECL = 2;
61 public static final int STATE_CDATA = 4;
63 public static final int STATE_INTERNAL = 8;
65 protected IDocument document;
73 protected int position;
77 protected boolean parsedtd;
79 protected Map tokens = new HashMap();
81 public XMLPartitionScanner(boolean parsedtd) {
82 this.parsedtd = parsedtd;
86 * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken()
88 public IToken nextToken() {
93 return nextTagToken();
96 return nextDeclToken();
99 return nextCDATAToken();
103 case ICharacterScanner.EOF:
104 state = STATE_DEFAULT;
105 return getToken(null);
109 case ICharacterScanner.EOF:
110 if (parsedtd || isInternal()) {
114 state = STATE_DEFAULT;
115 return getToken(XML_TAG);
118 return nextPIToken();
120 case '!': // <! <!DEFINITION or <![CDATA[ or <!--COMMENT
122 case ICharacterScanner.EOF:
123 state = STATE_DEFAULT;
124 return getToken(XML_TAG);
126 case '-': // <!- <!--COMMENT
128 case ICharacterScanner.EOF:
129 return nextDeclToken();
132 return nextCommentToken();
135 case '[': // <![ <![CDATA[ or <![%cond;[
137 return nextConditionalToken();
141 return nextCDATAToken();
145 return nextDeclToken();
148 if (parsedtd || isInternal()) {
154 return nextTagToken();
171 case ICharacterScanner.EOF:
172 state = STATE_DEFAULT;
173 return getToken(null);
176 if (parsedtd || isInternal()) {
178 case ICharacterScanner.EOF:
179 state = STATE_DEFAULT;
180 return getToken(null);
194 state &= STATE_INTERNAL;
195 return getToken(isInternal() ? DTD_INTERNAL : null);
202 if (position == offset) {
208 return getToken(DTD_INTERNAL);
214 private IToken nextTagToken() {
218 case ICharacterScanner.EOF:
220 state = STATE_DEFAULT;
221 return getToken(XML_TAG);
230 return getToken(XML_ATTRIBUTE);
237 case ICharacterScanner.EOF:
238 state = STATE_DEFAULT;
239 return getToken(XML_ATTRIBUTE);
251 case ICharacterScanner.EOF:
253 state = STATE_DEFAULT;
254 return getToken(XML_TAG);
261 return getToken(XML_TAG);
266 private IToken nextDeclToken() {
269 case ICharacterScanner.EOF:
270 state = STATE_DEFAULT;
271 return getToken(isInternal() ? DTD_INTERNAL_DECL : XML_DECL);
274 if (parsedtd || isInternal()) {
276 case ICharacterScanner.EOF:
277 state = STATE_DEFAULT;
278 return getToken(isInternal() ? DTD_INTERNAL : null);
293 state &= STATE_INTERNAL;
294 return getToken(isInternal() ? DTD_INTERNAL_DECL : XML_DECL);
296 case '[': // <!DOCTYPE xxx [dtd]>
298 state = STATE_INTERNAL;
299 return getToken(XML_DECL);
305 private IToken nextCommentToken() {
306 state &= STATE_INTERNAL;
310 case ICharacterScanner.EOF:
315 case ICharacterScanner.EOF:
320 case ICharacterScanner.EOF:
331 return getToken(isInternal() ? DTD_INTERNAL_COMMENT : XML_COMMENT);
334 private IToken nextPIToken() {
335 state &= STATE_INTERNAL;
339 case ICharacterScanner.EOF:
344 case ICharacterScanner.EOF:
353 return getToken(isInternal() ? DTD_INTERNAL_PI : XML_PI);
356 private IToken nextCDATAToken() {
357 state = STATE_DEFAULT;
361 case ICharacterScanner.EOF:
366 case ICharacterScanner.EOF:
371 case ICharacterScanner.EOF:
383 return getToken(XML_CDATA);
386 private IToken nextConditionalToken() {
387 state = STATE_DEFAULT;
393 case ICharacterScanner.EOF:
398 case ICharacterScanner.EOF:
403 case ICharacterScanner.EOF:
420 case ICharacterScanner.EOF:
425 case ICharacterScanner.EOF:
441 return getToken(DTD_CONDITIONAL);
444 private IToken getToken(String type) {
445 length = position - offset;
452 return Token.UNDEFINED;
455 IToken token = (IToken) tokens.get(type);
457 token = new Token(type);
458 tokens.put(type, token);
464 private boolean isInternal() {
465 return (state & STATE_INTERNAL) != 0;
469 if (position >= end) {
470 return ICharacterScanner.EOF;
474 return document.getChar(position++);
475 } catch (BadLocationException e) {
477 return ICharacterScanner.EOF;
481 private void unread() {
486 * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset()
488 public int getTokenOffset() {
489 Assert.isTrue(offset >= 0, Integer.toString(offset));
494 * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength()
496 public int getTokenLength() {
501 * @see org.eclipse.jface.text.rules.ITokenScanner#setRange(IDocument, int,
504 public void setRange(IDocument document, int offset, int length) {
505 this.document = document;
506 this.end = offset + length;
508 this.offset = offset;
509 this.position = offset;
512 this.state = STATE_DEFAULT;
516 * @see org.eclipse.jface.text.rules.IPartitionTokenScanner
518 // public void setPartialRange(IDocument document, int offset, int length,
519 // String contentType, int partitionOffset) {
520 // state = STATE_DEFAULT;
521 // if (partitionOffset > -1) {
522 // int delta = offset - partitionOffset;
524 // setRange(document, partitionOffset, length + delta);
528 // setRange(document, partitionOffset, length);
531 * @see org.eclipse.jface.text.rules.IPartitionTokenScanner
533 public void setPartialRange(IDocument document, int offset, int length,
534 String contentType, int partitionOffset) {
535 // boolean flag = false;
536 this.document = document;
537 this.end = offset + length;
539 // NB! Undocumented value: -1
540 if (partitionOffset >= 0) {
541 offset = partitionOffset;
545 this.offset = offset;
546 this.position = offset;
550 // state = STATE_DEFAULT;
553 if (contentType == XML_ATTRIBUTE) {
558 if (contentType == XML_TAG) {
559 state = isContinuationPartition() ? STATE_TAG : STATE_DEFAULT;
563 if (contentType == XML_DECL) {
564 state = isContinuationPartition() ? STATE_DECL : STATE_DEFAULT;
568 if (contentType == DTD_INTERNAL || contentType == DTD_INTERNAL_PI
569 || contentType == DTD_INTERNAL_DECL
570 || contentType == DTD_INTERNAL_COMMENT) {
571 state = STATE_INTERNAL;
575 state = STATE_DEFAULT;
578 private boolean isContinuationPartition() {
580 String type = document.getContentType(offset - 1);
582 if (type != IDocument.DEFAULT_CONTENT_TYPE) {
585 } catch (BadLocationException e) {