tests fix
[fedora-idea.git] / lang-impl / src / com / intellij / psi / templateLanguages / TemplateDataElementType.java
blob33490184c56c51d959e94c25956fb4306451d284
1 /*
2 * Copyright (c) 2000-2005 by JetBrains s.r.o. All Rights Reserved.
3 * Use is subject to license terms.
4 */
5 package com.intellij.psi.templateLanguages;
7 import com.intellij.lang.ASTNode;
8 import com.intellij.lang.Language;
9 import com.intellij.lang.LanguageParserDefinitions;
10 import com.intellij.lang.LanguageExtension;
11 import com.intellij.lexer.Lexer;
12 import com.intellij.lexer.MergingLexerAdapter;
13 import com.intellij.openapi.fileTypes.LanguageFileType;
14 import com.intellij.openapi.diagnostic.Logger;
15 import com.intellij.psi.FileViewProvider;
16 import com.intellij.psi.PsiFile;
17 import com.intellij.psi.PsiManager;
18 import com.intellij.psi.SingleRootFileViewProvider;
19 import com.intellij.psi.impl.source.DummyHolder;
20 import com.intellij.psi.impl.source.PsiFileImpl;
21 import com.intellij.psi.impl.source.parsing.ChameleonTransforming;
22 import com.intellij.psi.impl.source.tree.*;
23 import com.intellij.psi.tree.IElementType;
24 import com.intellij.psi.tree.IFileElementType;
25 import com.intellij.psi.tree.TokenSet;
26 import com.intellij.testFramework.LightVirtualFile;
27 import com.intellij.util.CharTable;
28 import com.intellij.util.LocalTimeCounter;
29 import org.jetbrains.annotations.NonNls;
30 import org.jetbrains.annotations.NotNull;
31 import org.jetbrains.annotations.Nullable;
33 import javax.swing.*;
35 /**
36 * @author peter
38 public class TemplateDataElementType extends IFileElementType implements ITemplateDataElementType {
39 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.templateLanguages.TemplateDataElementType");
41 private final static LanguageExtension<TreePatcher> TREE_PATCHER = new LanguageExtension<TreePatcher>("com.intellij.lang.treePatcher", new SimpleTreePatcher());
43 private final IElementType myTemplateElementType;
44 private final IElementType myOuterElementType;
46 public TemplateDataElementType(@NonNls String debugName, Language language, IElementType templateElementType, IElementType outerElementType) {
47 super(debugName, language);
48 myTemplateElementType = templateElementType;
49 myOuterElementType = outerElementType;
52 protected Lexer createBaseLexer(TemplateLanguageFileViewProvider viewProvider) {
53 return LanguageParserDefinitions.INSTANCE.forLanguage(viewProvider.getBaseLanguage()).createLexer(viewProvider.getManager().getProject());
56 protected LanguageFileType createTemplateFakeFileType(final Language language) {
57 return new TemplateFileType(language);
60 public ASTNode parseContents(ASTNode chameleon) {
61 final CharTable table = SharedImplUtil.findCharTableByTree(chameleon);
62 final FileElement treeElement = new DummyHolder(((TreeElement)chameleon).getManager(), null, table).getTreeElement();
63 final PsiFile file = (PsiFile)TreeUtil.getFileElement((TreeElement)chameleon).getPsi();
64 PsiFile originalFile = file.getOriginalFile();
65 if (originalFile == null) originalFile = file;
67 final TemplateLanguageFileViewProvider viewProvider = (TemplateLanguageFileViewProvider)originalFile.getViewProvider();
69 final Language language = viewProvider.getTemplateDataLanguage();
70 final CharSequence chars = ((LeafElement)chameleon).getInternedText();
72 final Lexer baseLexer = createBaseLexer(viewProvider);
73 final CharSequence templateText = createTemplateText(chars, baseLexer);
74 final PsiFile templateFile = createFromText(language, templateText, file.getManager());
76 final TreeElement parsed = ((PsiFileImpl)templateFile).calcTreeElement();
77 ChameleonTransforming.transformChildren(parsed, false);
79 Lexer langLexer = LanguageParserDefinitions.INSTANCE.forLanguage(language).createLexer(file.getProject());
80 final Lexer lexer = new MergingLexerAdapter(
81 new TemplateBlackAndWhiteLexer(createBaseLexer(viewProvider), langLexer, myTemplateElementType, myOuterElementType),
82 TokenSet.create(myTemplateElementType, myOuterElementType));
83 lexer.start(chars, 0, chars.length(),0);
84 insertOuters(parsed, lexer, table);
86 if (parsed != null) {
87 final TreeElement element = parsed.getFirstChildNode();
88 if (element != null) {
89 TreeUtil.addChildren(treeElement, element);
93 treeElement.clearCaches();
94 treeElement.subtreeChanged();
95 return treeElement.getFirstChildNode();
98 private CharSequence createTemplateText(CharSequence buf, Lexer lexer) {
99 StringBuilder result = new StringBuilder(buf.length());
100 lexer.start(buf, 0, buf.length(), 0);
102 while (lexer.getTokenType() != null) {
103 if (lexer.getTokenType() == myTemplateElementType) {
104 result.append(buf, lexer.getTokenStart(), lexer.getTokenEnd());
106 lexer.advance();
109 return result;
112 private void insertOuters(TreeElement root, Lexer lexer, final CharTable table) {
113 TreePatcher patcher = TREE_PATCHER.forLanguage(root.getPsi().getLanguage());
115 int treeOffset = 0;
116 LeafElement leaf = TreeUtil.findFirstLeaf(root);
117 while (lexer.getTokenType() != null) {
118 IElementType tt = lexer.getTokenType();
119 if (tt != myTemplateElementType) {
120 while (leaf != null && treeOffset < lexer.getTokenStart()) {
121 treeOffset += leaf.getTextLength();
122 if (treeOffset > lexer.getTokenStart()) {
123 if (leaf instanceof ChameleonElement) {
124 final ASTNode transformed = ChameleonTransforming.transform(leaf);
125 treeOffset -= leaf.getTextLength();
126 leaf = TreeUtil.findFirstLeaf(transformed);
127 continue;
129 leaf = patcher.split(leaf, leaf.getTextLength() - (treeOffset - lexer.getTokenStart()), table);
130 treeOffset = lexer.getTokenStart();
132 leaf = (LeafElement)TreeUtil.nextLeaf(leaf);
135 if (leaf == null) break;
137 final OuterLanguageElementImpl newLeaf = createOuterLanguageElement(lexer, table, myOuterElementType);
138 patcher.insert(leaf.getTreeParent(), leaf, newLeaf);
139 leaf.getTreeParent().subtreeChanged();
140 leaf = newLeaf;
142 lexer.advance();
145 if (lexer.getTokenType() != null) {
146 assert lexer.getTokenType() != myTemplateElementType;
147 final OuterLanguageElementImpl newLeaf = createOuterLanguageElement(lexer, table, myOuterElementType);
148 TreeUtil.addChildren((CompositeElement)root, newLeaf);
149 ((CompositeElement)root).subtreeChanged();
153 protected OuterLanguageElementImpl createOuterLanguageElement(final Lexer lexer, final CharTable table,
154 final IElementType outerElementType) {
155 final CharSequence buffer = lexer.getBufferSequence();
156 final int tokenStart = lexer.getTokenStart();
157 if (tokenStart < 0 || tokenStart > buffer.length()) {
158 LOG.assertTrue(false, "Invalid start: " + tokenStart + "; " + lexer);
160 final int tokenEnd = lexer.getTokenEnd();
161 if (tokenEnd < 0 || tokenEnd > buffer.length()) {
162 LOG.assertTrue(false, "Invalid end: " + tokenEnd + "; " + lexer);
165 return new OuterLanguageElementImpl(outerElementType, buffer, tokenStart, tokenEnd, table);
168 private PsiFile createFromText(final Language language, CharSequence text, PsiManager manager) {
169 @NonNls
170 final LightVirtualFile virtualFile = new LightVirtualFile("foo", createTemplateFakeFileType(language), text, LocalTimeCounter.currentTime());
172 FileViewProvider viewProvider = new SingleRootFileViewProvider(manager, virtualFile, false) {
173 @NotNull
174 public Language getBaseLanguage() {
175 return language;
179 return viewProvider.getPsi(language);
182 protected static class TemplateFileType extends LanguageFileType {
183 private final Language myLanguage;
185 public TemplateFileType(final Language language) {
186 super(language);
187 myLanguage = language;
190 @NotNull
191 public String getDefaultExtension() {
192 return "";
195 @NotNull
196 @NonNls
197 public String getDescription() {
198 return "fake for language" + myLanguage.getID();
201 @Nullable
202 public Icon getIcon() {
203 return null;
206 @NotNull
207 @NonNls
208 public String getName() {
209 return myLanguage.getID();