intial source from ttp://www.sf.net/projects/wdte
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.css.ui / src / net / sourceforge / phpeclipse / css / ui / internal / text / CssCodeScanner.java
diff --git a/archive/net.sourceforge.phpeclipse.css.ui/src/net/sourceforge/phpeclipse/css/ui/internal/text/CssCodeScanner.java b/archive/net.sourceforge.phpeclipse.css.ui/src/net/sourceforge/phpeclipse/css/ui/internal/text/CssCodeScanner.java
new file mode 100644 (file)
index 0000000..62447eb
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2003-2004 Christopher Lenz and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     Christopher Lenz - initial API and implementation
+ * 
+ * $Id: CssCodeScanner.java,v 1.1 2004-09-02 18:11:48 jsurfer Exp $
+ */
+
+package net.sourceforge.phpeclipse.css.ui.internal.text;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import net.sourceforge.phpeclipse.css.core.internal.text.CssTextUtils;
+import net.sourceforge.phpeclipse.css.core.profiles.IProfile;
+import net.sourceforge.phpeclipse.css.ui.internal.CssUIPreferences;
+import net.sourceforge.phpeclipse.css.ui.text.IColorManager;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.rules.ICharacterScanner;
+import org.eclipse.jface.text.rules.IRule;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.IWhitespaceDetector;
+import org.eclipse.jface.text.rules.Token;
+import org.eclipse.jface.text.rules.WhitespaceRule;
+
+/**
+ * Rule based scanner responsible for syntax highlighting CSS source.
+ */
+public class CssCodeScanner extends AbstractCssScanner {
+
+       // Inner Classes -----------------------------------------------------------
+
+       /**
+        * Custom rule that detects the SGML/XML comment delimiters
+        * (<code>&lt;!--</code> and <code>--&gt;</code> which are allowed at the 
+        * beginning and the end of CSS content.
+        */
+       private class CdoCdcRule implements IRule {
+
+               /**
+                * The associated token.
+                */
+               private IToken token;
+
+               /**
+                * Constructor.
+                * 
+                * @param token the associated token
+                */
+               public CdoCdcRule(IToken token) {
+                       this.token = token;
+               }
+
+               /**
+                * @see IRule#evaluate(ICharacterScanner)
+                */
+               public synchronized IToken evaluate(ICharacterScanner scanner) {
+                       IToken retVal = Token.UNDEFINED;
+                       int count = 1;
+                       int c = scanner.read();
+                       if (c == '<') {
+                               count++;
+                               c = scanner.read();
+                               if (c == '!') {
+                                       count++;
+                                       c = scanner.read();
+                                       if (c == '-') {
+                                               count++;
+                                               c = scanner.read();
+                                               if (c == '-') {
+                                                       return token;
+                                               }
+                                       }
+                               }
+                       } else if (c == '-') {
+                               count++;
+                               c = scanner.read();
+                               if (c == '-') {
+                                       count++;
+                                       c = scanner.read();
+                                       if (c == '>') {
+                                               return token;
+                                       }
+                               }
+                       }
+                       while (count-- > 0) {
+                               scanner.unread();
+                       }
+                       return retVal;
+               }
+               
+       }
+
+       /**
+        * Custom rule that can detect an at-keyword such as <code>@import</code>.
+        */
+       private class AtKeywordRule implements IRule {
+
+               /**
+                * The associated token.
+                */
+               private IToken token;
+
+               /**
+                * Collection of known at-keywords.
+                */
+               private Collection atKeywords;
+
+               /**
+                * Constructor.
+                * 
+                * @param token the associated token
+                */
+               public AtKeywordRule(IToken token) {
+                       this.token = token;
+                       atKeywords = getProfile().getAtKeywords();
+               }
+
+               /**
+                * @see IRule#evaluate(ICharacterScanner)
+                */
+               public synchronized IToken evaluate(ICharacterScanner scanner) {
+                       IToken retVal = Token.UNDEFINED;
+                       int count = 1;
+                       int c = scanner.read();
+                       if (c == '@') {
+                               c = scanner.read();
+                               if (CssTextUtils.isCssIdentifierStart((char) c)) {
+                                       resetBuffer();
+                                       do {
+                                               appendToBuffer((char) c);
+                                               c = scanner.read();
+                                               count++;
+                                       } while (CssTextUtils.isCssIdentifierPart((char) c));
+                                       String candidate = getBufferContent().toLowerCase();
+                                       if (atKeywords.contains(candidate)) {
+                                               return token;
+                                       }
+                               }
+                       }
+                       while (count-- > 0) {
+                               scanner.unread();
+                       }
+                       return retVal;
+               }
+               
+       }
+
+       /**
+        * Custom rule that can detect a known property.
+        */
+       private class PropertyRule implements IRule {
+
+               /**
+                * The associated token.
+                */
+               private IToken token;
+
+               /**
+                * Collection of known properties.
+                */
+               private Collection properties;
+
+               /**
+                * Constructor.
+                * 
+                * @param token the associated token
+                */
+               public PropertyRule(IToken token) {
+                       this.token = token;
+                       properties = getProfile().getProperties();
+               }
+
+               /**
+                * @see IRule#evaluate(ICharacterScanner)
+                */
+               public synchronized IToken evaluate(ICharacterScanner scanner) {
+                       IToken retVal = Token.UNDEFINED;
+                       int count = 1;
+                       int c = scanner.read();
+                       if (CssTextUtils.isCssIdentifierStart((char) c)) {
+                               resetBuffer();
+                               do {
+                                       appendToBuffer((char) c);
+                                       c = scanner.read();
+                                       count++;
+                               } while (CssTextUtils.isCssIdentifierPart((char) c));
+                               String candidate = getBufferContent().toLowerCase();
+                               if (properties.contains(candidate)) {
+                                       while (CssTextUtils.isCssWhitespace((char) c)) {
+                                               c = scanner.read();
+                                               count++;
+                                       }
+                                       if (c == ':') {
+                                               scanner.unread();
+                                               return token;
+                                       }
+                               }
+                       }
+                       while (count-- > 0) {
+                               scanner.unread();
+                       }
+                       return retVal;
+               }
+               
+       }
+
+       /**
+        * Custom rule that can detect a pseudo-class in a selector.
+        */
+       private class PseudoClassRule implements IRule {
+
+               /**
+                * The associated token.
+                */
+               private IToken token;
+
+               /**
+                * Collection of known pseudo-classes.
+                */
+               private Collection pseudoClasses;
+
+               /**
+                * Constructor.
+                * 
+                * @param token the associated token
+                */
+               public PseudoClassRule(IToken token) {
+                       this.token = token;
+                       pseudoClasses = getProfile().getPseudoClassNames();
+               }
+
+               /**
+                * @see IRule#evaluate(ICharacterScanner)
+                */
+               public synchronized IToken evaluate(ICharacterScanner scanner) {
+                       IToken retVal = Token.UNDEFINED;
+                       int count = 1;
+                       int c = scanner.read();
+                       if (c == ':') {
+                               c = scanner.read();
+                               if (CssTextUtils.isCssIdentifierStart((char) c)) {
+                                       resetBuffer();
+                                       do {
+                                               appendToBuffer((char) c);
+                                               c = scanner.read();
+                                               count++;
+                                       } while (CssTextUtils.isCssIdentifierPart((char) c));
+                                       String candidate = getBufferContent().toLowerCase();
+                                       if (pseudoClasses.contains(candidate)) {
+                                               return token;
+                                       }
+                               }
+                       }
+                       while (count-- > 0) {
+                               scanner.unread();
+                       }
+                       return retVal;
+               }
+               
+       }
+
+       /**
+        * Detects CSS white space.
+        */
+       private static class WhitespaceDetector implements IWhitespaceDetector {
+
+               /**
+                * @see IWhitespaceDetector#isWhitespace(char)
+                */
+               public boolean isWhitespace(char c) {
+                       return CssTextUtils.isCssWhitespace(c);
+               }
+
+       }
+
+       // Instance Variables ------------------------------------------------------
+
+       /**
+        * The current CSS profile.
+        */
+       private IProfile profile;
+
+       /**
+        * Shared buffer used by the word detectors.
+        */
+       private StringBuffer buffer = new StringBuffer();
+
+       // Constructors ------------------------------------------------------------
+
+       /**
+        * Constructor.
+        * 
+        * @param store The preference store
+        * @param manager The color manager
+        * @param profile The CSS profile to use
+        */
+       public CssCodeScanner(IPreferenceStore store, IColorManager manager, 
+               IProfile profile) {
+               super(store, manager);
+               this.profile = profile;
+
+               List rules = new ArrayList();
+
+               rules.add(new WhitespaceRule(new WhitespaceDetector()));
+
+               rules.add(new CdoCdcRule(createToken(
+                       CssUIPreferences.EDITOR_COMMENT_COLOR,
+                       CssUIPreferences.EDITOR_COMMENT_BOLD)));
+               rules.add(new AtKeywordRule(createToken(
+                       CssUIPreferences.EDITOR_AT_KEYWORD_COLOR,
+                       CssUIPreferences.EDITOR_AT_KEYWORD_BOLD)));
+               rules.add(new PropertyRule(createToken(
+                       CssUIPreferences.EDITOR_PROPERTY_COLOR,
+                       CssUIPreferences.EDITOR_PROPERTY_BOLD)));
+               rules.add(new PseudoClassRule(createToken(
+                       CssUIPreferences.EDITOR_PSEUDO_CLASS_COLOR,
+                       CssUIPreferences.EDITOR_PSEUDO_CLASS_BOLD)));
+
+               setRules((IRule[]) rules.toArray(new IRule[rules.size()]));
+
+               setDefaultReturnToken(createToken(
+                       CssUIPreferences.EDITOR_DEFAULT_COLOR,
+                       CssUIPreferences.EDITOR_DEFAULT_BOLD));
+       }
+
+       // Private Methods ---------------------------------------------------------
+
+       private IProfile getProfile() {
+               return profile;
+       }
+
+       private void appendToBuffer(char c) {
+               buffer.append(c);
+       }
+
+       private String getBufferContent() {
+               return buffer.toString();
+       }
+       
+       private void resetBuffer() {
+               buffer.setLength(0);
+       }
+
+}