/* * 09/03/2005 * * CSSTokenMaker.java - Token maker for CSS 3 files. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.rsyntaxtextarea.modes; import java.io.*; import javax.swing.text.Segment; import org.fife.ui.rsyntaxtextarea.*; /** * This class splits up text into tokens representing a CSS 3 file. It's * written with a few extra internal states so that it can easily be copy * and pasted into HTML, PHP, and JSP TokenMakres when it is updated.

* * This implementation was created using * JFlex 1.4.1; however, the generated file * was modified for performance. Memory allocation needs to be almost * completely removed to be competitive with the handwritten lexers (subclasses * of AbstractTokenMaker, so this class has been modified so that * Strings are never allocated (via yytext()), and the scanner never has to * worry about refilling its buffer (needlessly copying chars around). * We can achieve this because RText always scans exactly 1 line of tokens at a * time, and hands the scanner this line as an array of characters (a Segment * really). Since tokens contain pointers to char arrays instead of Strings * holding their contents, there is no need for allocating new memory for * Strings.

* * The actual algorithm generated for scanning has, of course, not been * modified.

* * If you wish to regenerate this file yourself, keep in mind the following: *

* * @author Robert Futrell * @version 0.4 * */ %% %public %class CSSTokenMaker %extends AbstractJFlexTokenMaker %implements TokenMaker %unicode %type org.fife.ui.rsyntaxtextarea.Token %{ /** * Internal type denoting a line ending in a CSS property. */ public static final int INTERNAL_CSS_PROPERTY = -1; /** * Internal type denoting a line ending in a CSS property value. */ public static final int INTERNAL_CSS_VALUE = -2; /** * Internal type denoting line ending in a CSS double-quote string. * The state to return to is embedded in the actual end token type. */ public static final int INTERNAL_CSS_STRING = -(1<<11); /** * Internal type denoting line ending in a CSS single-quote string. * The state to return to is embedded in the actual end token type. */ public static final int INTERNAL_CSS_CHAR = -(2<<11); /** * Internal type denoting line ending in a CSS multi-line comment. * The state to return to is embedded in the actual end token type. */ public static final int INTERNAL_CSS_MLC = -(3<<11); /** * The state previous CSS-related state we were in before going into a CSS * string, multi-line comment, etc. */ private int cssPrevState; /** * Constructor. This must be here because JFlex does not generate a * no-parameter constructor. */ public CSSTokenMaker() { super(); } /** * Adds the token specified to the current linked list of tokens as an * "end token;" that is, at zzMarkedPos. * * @param tokenType The token's type. */ private void addEndToken(int tokenType) { addToken(zzMarkedPos,zzMarkedPos, tokenType); } /** * Adds the token specified to the current linked list of tokens. * * @param tokenType The token's type. * @see #addToken(int, int, int) */ private void addHyperlinkToken(int start, int end, int tokenType) { int so = start + offsetShift; addToken(zzBuffer, start,end, tokenType, so, true); } /** * Adds the token specified to the current linked list of tokens. * * @param tokenType The token's type. */ private void addToken(int tokenType) { addToken(zzStartRead, zzMarkedPos-1, tokenType); } /** * Adds the token specified to the current linked list of tokens. * * @param tokenType The token's type. */ private void addToken(int start, int end, int tokenType) { int so = start + offsetShift; addToken(zzBuffer, start,end, tokenType, so); } /** * Adds the token specified to the current linked list of tokens. * * @param array The character array. * @param start The starting offset in the array. * @param end The ending offset in the array. * @param tokenType The token's type. * @param startOffset The offset in the document at which this token * occurs. */ public void addToken(char[] array, int start, int end, int tokenType, int startOffset) { super.addToken(array, start,end, tokenType, startOffset); zzStartRead = zzMarkedPos; } /** * Returns true since CSS uses curly braces. * * @return true always. */ public boolean getCurlyBracesDenoteCodeBlocks() { return true; } /** * Returns the first token in the linked list of tokens generated * from text. This method must be implemented by * subclasses so they can correctly implement syntax highlighting. * * @param text The text from which to get tokens. * @param initialTokenType The token type we should start with. * @param startOffset The offset into the document at which * text starts. * @return The first Token in a linked list representing * the syntax highlighted text. */ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { resetTokenList(); this.offsetShift = -text.offset + startOffset; cssPrevState = YYINITIAL; // Shouldn't be necessary // Start off in the proper state. int state = Token.NULL; switch (initialTokenType) { case Token.LITERAL_STRING_DOUBLE_QUOTE: state = CSS_STRING; break; case Token.LITERAL_CHAR: state = CSS_CHAR_LITERAL; break; case Token.COMMENT_MULTILINE: state = CSS_C_STYLE_COMMENT; break; case INTERNAL_CSS_PROPERTY: state = CSS_PROPERTY; break; case INTERNAL_CSS_VALUE: state = CSS_VALUE; break; default: if (initialTokenType<-1024) { int main = -(-initialTokenType & 0xffffff00); switch (main) { default: // Should never happen case INTERNAL_CSS_STRING: state = CSS_STRING; break; case INTERNAL_CSS_CHAR: state = CSS_CHAR_LITERAL; break; case INTERNAL_CSS_MLC: state = CSS_C_STYLE_COMMENT; break; } cssPrevState = -initialTokenType&0xff; } else { state = Token.NULL; } } start = text.offset; s = text; try { yyreset(zzReader); yybegin(state); return yylex(); } catch (IOException ioe) { ioe.printStackTrace(); return new DefaultToken(); } } /** * Refills the input buffer. * * @return true if EOF was reached, otherwise * false. */ private boolean zzRefill() { return zzCurrentPos>=s.offset+s.count; } /** * Resets the scanner to read from a new input stream. * Does not close the old reader. * * All internal variables are reset, the old input stream * cannot be reused (internal buffer is discarded and lost). * Lexical state is set to YY_INITIAL. * * @param reader the new input stream */ public final void yyreset(java.io.Reader reader) { // 's' has been updated. zzBuffer = s.array; /* * We replaced the line below with the two below it because zzRefill * no longer "refills" the buffer (since the way we do it, it's always * "full" the first time through, since it points to the segment's * array). So, we assign zzEndRead here. */ //zzStartRead = zzEndRead = s.offset; zzStartRead = s.offset; zzEndRead = zzStartRead + s.count - 1; zzCurrentPos = zzMarkedPos = zzPushbackPos = s.offset; zzLexicalState = YYINITIAL; zzReader = reader; zzAtBOL = true; zzAtEOF = false; } %} Digit = ([0-9]) Letter = ([A-Za-z]) LetterOrUnderscore = ({Letter}|[_]) LetterOrUnderscoreOrDash = ({LetterOrUnderscore}|[\-]) CSS_SelectorPiece = (("*"|"."|{LetterOrUnderscoreOrDash})({LetterOrUnderscoreOrDash}|"."|{Digit})*) CSS_PseudoClass = (":"("root"|"nth-child"|"nth-last-child"|"nth-of-type"|"nth-last-of-type"|"first-child"|"last-child"|"first-of-type"|"last-of-type"|"only-child"|"only-of-type"|"empty"|"link"|"visited"|"active"|"hover"|"focus"|"target"|"lang"|"enabled"|"disabled"|"checked"|":first-line"|":first-letter"|":before"|":after"|"not")) CSS_AtKeyword = ("@"{CSS_SelectorPiece}) CSS_Id = ("#"{CSS_SelectorPiece}) CSS_Separator = ([;\(\)\[\]]) WhiteSpace = ([ \t]+) MlcStart = ("/*") MlcEnd = ("*/") CSS_Property = ([\*]?{LetterOrUnderscoreOrDash}({LetterOrUnderscoreOrDash}|{Digit})*) CSS_ValueChar = ({LetterOrUnderscoreOrDash}|[\\/]) CSS_Value = ({CSS_ValueChar}*) CSS_Function = ({CSS_Value}\() CSS_Digits = ([\-]?{Digit}+([0-9\.]+)?(pt|pc|in|mm|cm|em|ex|px|ms|s|%)?) CSS_Hex = ("#"[0-9a-fA-F]+) CSS_Number = ({CSS_Digits}|{CSS_Hex}) URLGenDelim = ([:\/\?#\[\]@]) URLSubDelim = ([\!\$&'\(\)\*\+,;=]) URLUnreserved = ({LetterOrUnderscore}|{Digit}|[\-\.\~]) URLCharacter = ({URLGenDelim}|{URLSubDelim}|{URLUnreserved}|[%]) URLCharacters = ({URLCharacter}*) URLEndCharacter = ([\/\$]|{Letter}|{Digit}) URL = (((https?|f(tp|ile))"://"|"www.")({URLCharacters}{URLEndCharacter})?) %state CSS_PROPERTY %state CSS_VALUE %state CSS_STRING %state CSS_CHAR_LITERAL %state CSS_C_STYLE_COMMENT %% { {CSS_SelectorPiece} { addToken(Token.DATA_TYPE); } {CSS_PseudoClass} { addToken(Token.RESERVED_WORD); } ":" { /* Unknown pseudo class */ addToken(Token.DATA_TYPE); } {CSS_AtKeyword} { addToken(Token.REGEX); } {CSS_Id} { addToken(Token.VARIABLE); } "{" { addToken(Token.SEPARATOR); yybegin(CSS_PROPERTY); } [,] { addToken(Token.IDENTIFIER); } \" { start = zzMarkedPos-1; cssPrevState = zzLexicalState; yybegin(CSS_STRING); } \' { start = zzMarkedPos-1; cssPrevState = zzLexicalState; yybegin(CSS_CHAR_LITERAL); } [+>~\^$\|=] { addToken(Token.OPERATOR); } {CSS_Separator} { addToken(Token.SEPARATOR); } {WhiteSpace} { addToken(Token.WHITESPACE); } {MlcStart} { start = zzMarkedPos-2; cssPrevState = zzLexicalState; yybegin(CSS_C_STYLE_COMMENT); } . { /*System.out.println("yyinitial: " + yytext());*/ addToken(Token.IDENTIFIER); } "\n" | <> { addNullToken(); return firstToken; } } { {CSS_Property} { addToken(Token.RESERVED_WORD); } "}" { addToken(Token.SEPARATOR); yybegin(YYINITIAL); } ":" { addToken(Token.OPERATOR); yybegin(CSS_VALUE); } {WhiteSpace} { addToken(Token.WHITESPACE); } {MlcStart} { start = zzMarkedPos-2; cssPrevState = zzLexicalState; yybegin(CSS_C_STYLE_COMMENT); } . { /*System.out.println("css_property: " + yytext());*/ addToken(Token.IDENTIFIER); } "\n" | <> { addEndToken(INTERNAL_CSS_PROPERTY); return firstToken; } } { {CSS_Value} { addToken(Token.IDENTIFIER); } "!important" { addToken(Token.ANNOTATION); } {CSS_Function} { int temp = zzMarkedPos - 2; addToken(zzStartRead, temp, Token.FUNCTION); addToken(zzMarkedPos-1, zzMarkedPos-1, Token.SEPARATOR); zzStartRead = zzCurrentPos = zzMarkedPos; } {CSS_Number} { addToken(Token.LITERAL_NUMBER_DECIMAL_INT); } \" { start = zzMarkedPos-1; cssPrevState = zzLexicalState; yybegin(CSS_STRING); } \' { start = zzMarkedPos-1; cssPrevState = zzLexicalState; yybegin(CSS_CHAR_LITERAL); } ")" { /* End of a function */ addToken(Token.SEPARATOR); } [;] { addToken(Token.OPERATOR); yybegin(CSS_PROPERTY); } [,\.] { addToken(Token.IDENTIFIER); } "}" { addToken(Token.SEPARATOR); yybegin(YYINITIAL); } {WhiteSpace} { addToken(Token.WHITESPACE); } {MlcStart} { start = zzMarkedPos-2; cssPrevState = zzLexicalState; yybegin(CSS_C_STYLE_COMMENT); } . { /*System.out.println("css_value: " + yytext());*/ addToken(Token.IDENTIFIER); } "\n" | <> { addEndToken(INTERNAL_CSS_VALUE); return firstToken; } } { [^\n\\\"]+ {} \\.? { /* Skip escaped chars. */ } \" { addToken(start,zzStartRead, Token.LITERAL_STRING_DOUBLE_QUOTE); yybegin(cssPrevState); } \n | <> { addToken(start,zzStartRead-1, Token.LITERAL_STRING_DOUBLE_QUOTE); addEndToken(INTERNAL_CSS_STRING - cssPrevState); return firstToken; } } { [^\n\\\']+ {} \\.? { /* Skip escaped chars. */ } \' { addToken(start,zzStartRead, Token.LITERAL_CHAR); yybegin(cssPrevState); } \n | <> { addToken(start,zzStartRead-1, Token.LITERAL_CHAR); addEndToken(INTERNAL_CSS_CHAR - cssPrevState); return firstToken; } } { [^hwf\n\*]+ {} {URL} { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.COMMENT_MULTILINE); addHyperlinkToken(temp,zzMarkedPos-1, Token.COMMENT_MULTILINE); start = zzMarkedPos; } [hwf] {} {MlcEnd} { addToken(start,zzStartRead+1, Token.COMMENT_MULTILINE); yybegin(cssPrevState); } \* {} \n | <> { addToken(start,zzStartRead-1, Token.COMMENT_MULTILINE); addEndToken(INTERNAL_CSS_MLC - cssPrevState); return firstToken; } }