2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.lexer
;
18 import com
.intellij
.openapi
.diagnostic
.Logger
;
19 import com
.intellij
.openapi
.fileTypes
.FileType
;
20 import com
.intellij
.openapi
.fileTypes
.SyntaxHighlighter
;
21 import com
.intellij
.psi
.tree
.IElementType
;
22 import com
.intellij
.psi
.xml
.XmlTokenType
;
23 import org
.jetbrains
.annotations
.Nullable
;
25 public class HtmlHighlightingLexer
extends BaseHtmlLexer
{
26 private static final Logger LOG
= Logger
.getInstance("#com.intellij.lexer.HtmlHighlightingLexer");
28 private static final int EMBEDDED_LEXER_ON
= 0x1 << BASE_STATE_SHIFT
;
29 private static final int EMBEDDED_LEXER_STATE_SHIFT
= BASE_STATE_SHIFT
+ 1;
31 private Lexer embeddedLexer
;
32 private Lexer styleLexer
;
33 private Lexer scriptLexer
;
34 protected Lexer elLexer
;
35 private boolean hasNoEmbeddments
;
36 private static FileType ourStyleFileType
;
37 private static FileType ourScriptFileType
;
39 public class XmlEmbeddmentHandler
implements TokenHandler
{
40 public void handleElement(Lexer lexer
) {
41 if (!hasSeenStyle() && !hasSeenScript() || hasNoEmbeddments
) return;
42 final IElementType tokenType
= lexer
.getTokenType();
44 if ((tokenType
==XmlTokenType
.XML_ATTRIBUTE_VALUE_TOKEN
&& hasSeenAttribute()) ||
45 (tokenType
==XmlTokenType
.XML_DATA_CHARACTERS
&& hasSeenTag()) ||
46 tokenType
==XmlTokenType
.XML_COMMENT_CHARACTERS
&& hasSeenTag()
50 if (embeddedLexer
!=null) {
53 HtmlHighlightingLexer
.super.getTokenStart(),
54 skipToTheEndOfTheEmbeddment(),
55 embeddedLexer
instanceof EmbedmentLexer ?
((EmbedmentLexer
)embeddedLexer
).getEmbeddedInitialState(tokenType
) : 0
58 if (embeddedLexer
.getTokenType() == null) {
59 // no content for embeddment
67 public class ElEmbeddmentHandler
implements TokenHandler
{
68 public void handleElement(Lexer lexer
) {
70 if (embeddedLexer
!= null) {
71 embeddedLexer
.start(getBufferSequence(), HtmlHighlightingLexer
.super.getTokenStart(), HtmlHighlightingLexer
.super.getTokenEnd());
76 public HtmlHighlightingLexer() {
77 this(new MergingLexerAdapter(new FlexAdapter(new _HtmlLexer()),TOKENS_TO_MERGE
),true);
80 protected HtmlHighlightingLexer(Lexer lexer
, boolean caseInsensitive
) {
81 super(lexer
,caseInsensitive
);
83 XmlEmbeddmentHandler value
= new XmlEmbeddmentHandler();
84 registerHandler(XmlTokenType
.XML_ATTRIBUTE_VALUE_TOKEN
,value
);
85 registerHandler(XmlTokenType
.XML_DATA_CHARACTERS
,value
);
86 registerHandler(XmlTokenType
.XML_COMMENT_CHARACTERS
,value
);
89 public void start(CharSequence buffer
, int startOffset
, int endOffset
, int initialState
) {
90 super.start(buffer
, startOffset
, endOffset
, initialState
);
92 if ((initialState
& EMBEDDED_LEXER_ON
)!=0) {
93 int state
= initialState
>> EMBEDDED_LEXER_STATE_SHIFT
;
95 LOG
.assertTrue(embeddedLexer
!=null);
96 embeddedLexer
.start(buffer
,startOffset
,skipToTheEndOfTheEmbeddment(),state
);
102 private void setEmbeddedLexer() {
103 Lexer newLexer
= null;
104 if (hasSeenStyle()) {
105 if (styleLexer
==null) {
106 styleLexer
= (ourStyleFileType
!=null)? SyntaxHighlighter
.PROVIDER
.create(ourStyleFileType
, null, null).getHighlightingLexer():null;
109 newLexer
= styleLexer
;
110 } else if (hasSeenScript()) {
111 if (scriptLexer
==null) {
112 scriptLexer
= (ourScriptFileType
!=null)? SyntaxHighlighter
.PROVIDER
.create(ourScriptFileType
, null, null).getHighlightingLexer():null;
114 newLexer
= scriptLexer
;
115 } else newLexer
= createELLexer(newLexer
);
117 if (newLexer
!=null) {
118 embeddedLexer
= newLexer
;
123 protected Lexer
createELLexer(Lexer newLexer
) {
127 public void advance() {
128 if (embeddedLexer
!=null) {
129 embeddedLexer
.advance();
130 if (embeddedLexer
.getTokenType()==null) {
135 if (embeddedLexer
==null) {
140 public IElementType
getTokenType() {
141 if (embeddedLexer
!=null) {
142 return embeddedLexer
.getTokenType();
144 IElementType tokenType
= super.getTokenType();
146 // TODO: fix no DOCTYPE highlighting
147 if (tokenType
== null) return tokenType
;
149 if (tokenType
==XmlTokenType
.XML_NAME
) {
150 // we need to convert single xml_name for tag name and attribute name into to separate
151 // lex types for the highlighting!
152 final int state
= getState() & BASE_STATE_MASK
;
154 if (isHtmlTagState(state
)) {
155 tokenType
= XmlTokenType
.XML_TAG_NAME
;
158 else if (tokenType
== XmlTokenType
.XML_WHITE_SPACE
|| tokenType
== XmlTokenType
.XML_REAL_WHITE_SPACE
) {
159 if (hasSeenTag() && (hasSeenStyle() || hasSeenScript())) {
160 tokenType
= XmlTokenType
.XML_WHITE_SPACE
;
162 tokenType
= (getState()!=0)?XmlTokenType
.TAG_WHITE_SPACE
:XmlTokenType
.XML_REAL_WHITE_SPACE
;
164 } else if (tokenType
== XmlTokenType
.XML_CHAR_ENTITY_REF
||
165 tokenType
== XmlTokenType
.XML_ENTITY_REF_TOKEN
167 // we need to convert char entity ref & entity ref in comments as comment chars
168 final int state
= getState() & BASE_STATE_MASK
;
169 if (state
== _HtmlLexer
.COMMENT
) return XmlTokenType
.XML_COMMENT_CHARACTERS
;
175 public int getTokenStart() {
176 if (embeddedLexer
!=null) {
177 return embeddedLexer
.getTokenStart();
179 return super.getTokenStart();
183 public int getTokenEnd() {
184 if (embeddedLexer
!=null) {
185 return embeddedLexer
.getTokenEnd();
187 return super.getTokenEnd();
191 public static final void registerStyleFileType(FileType fileType
) {
192 ourStyleFileType
= fileType
;
195 public static void registerScriptFileType(FileType _scriptFileType
) {
196 ourScriptFileType
= _scriptFileType
;
199 public int getState() {
200 int state
= super.getState();
202 state
|= ((embeddedLexer
!=null)?EMBEDDED_LEXER_ON
:0);
203 if (embeddedLexer
!=null) state
|= (embeddedLexer
.getState() << EMBEDDED_LEXER_STATE_SHIFT
);
208 protected boolean isHtmlTagState(int state
) {
209 return state
== _HtmlLexer
.START_TAG_NAME
|| state
== _HtmlLexer
.END_TAG_NAME
||
210 state
== _HtmlLexer
.START_TAG_NAME2
|| state
== _HtmlLexer
.END_TAG_NAME2
;
213 public void setHasNoEmbeddments(boolean hasNoEmbeddments
) {
214 this.hasNoEmbeddments
= hasNoEmbeddments
;