Don't pass five parameters to LeafElement's constuctor to initialize single myText...
[fedora-idea.git] / lang-impl / src / com / intellij / psi / templateLanguages / TemplateDataElementType.java
blobbe003760d58d61f61024c10d1a4f9061b6d06566
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.LanguageExtension;
10 import com.intellij.lang.LanguageParserDefinitions;
11 import com.intellij.lexer.Lexer;
12 import com.intellij.lexer.MergingLexerAdapter;
13 import com.intellij.openapi.diagnostic.Logger;
14 import com.intellij.openapi.fileTypes.LanguageFileType;
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();
66 final TemplateLanguageFileViewProvider viewProvider = (TemplateLanguageFileViewProvider)originalFile.getViewProvider();
68 final Language language = viewProvider.getTemplateDataLanguage();
69 final CharSequence chars = ((LeafElement)chameleon).getInternedText();
71 final Lexer baseLexer = createBaseLexer(viewProvider);
72 final CharSequence templateText = createTemplateText(chars, baseLexer);
73 final PsiFile templateFile = createFromText(language, templateText, file.getManager());
75 final TreeElement parsed = ((PsiFileImpl)templateFile).calcTreeElement();
76 ChameleonTransforming.transformChildren(parsed, false);
78 Lexer langLexer = LanguageParserDefinitions.INSTANCE.forLanguage(language).createLexer(file.getProject());
79 final Lexer lexer = new MergingLexerAdapter(
80 new TemplateBlackAndWhiteLexer(createBaseLexer(viewProvider), langLexer, myTemplateElementType, myOuterElementType),
81 TokenSet.create(myTemplateElementType, myOuterElementType));
82 lexer.start(chars, 0, chars.length(),0);
83 insertOuters(parsed, lexer, table);
85 if (parsed != null) {
86 final TreeElement element = parsed.getFirstChildNode();
87 if (element != null) {
88 treeElement.rawAddChildren(element);
92 treeElement.clearCaches();
93 treeElement.subtreeChanged();
94 return treeElement.getFirstChildNode();
97 private CharSequence createTemplateText(CharSequence buf, Lexer lexer) {
98 StringBuilder result = new StringBuilder(buf.length());
99 lexer.start(buf, 0, buf.length(), 0);
101 while (lexer.getTokenType() != null) {
102 if (lexer.getTokenType() == myTemplateElementType) {
103 result.append(buf, lexer.getTokenStart(), lexer.getTokenEnd());
105 lexer.advance();
108 return result;
111 private void insertOuters(TreeElement root, Lexer lexer, final CharTable table) {
112 TreePatcher patcher = TREE_PATCHER.forLanguage(root.getPsi().getLanguage());
114 int treeOffset = 0;
115 LeafElement leaf = TreeUtil.findFirstLeaf(root);
116 while (lexer.getTokenType() != null) {
117 IElementType tt = lexer.getTokenType();
118 if (tt != myTemplateElementType) {
119 while (leaf != null && treeOffset < lexer.getTokenStart()) {
120 treeOffset += leaf.getTextLength();
121 if (treeOffset > lexer.getTokenStart()) {
122 if (leaf instanceof ChameleonElement) {
123 final ASTNode transformed = ChameleonTransforming.transform(leaf);
124 treeOffset -= leaf.getTextLength();
125 leaf = TreeUtil.findFirstLeaf(transformed);
126 continue;
128 leaf = patcher.split(leaf, leaf.getTextLength() - (treeOffset - lexer.getTokenStart()), table);
129 treeOffset = lexer.getTokenStart();
131 leaf = (LeafElement)TreeUtil.nextLeaf(leaf);
134 if (leaf == null) break;
136 final OuterLanguageElementImpl newLeaf = createOuterLanguageElement(lexer, table, myOuterElementType);
137 patcher.insert(leaf.getTreeParent(), leaf, newLeaf);
138 leaf.getTreeParent().subtreeChanged();
139 leaf = newLeaf;
141 lexer.advance();
144 if (lexer.getTokenType() != null) {
145 assert lexer.getTokenType() != myTemplateElementType;
146 final OuterLanguageElementImpl newLeaf = createOuterLanguageElement(lexer, table, myOuterElementType);
147 ((CompositeElement)root).rawAddChildren(newLeaf);
148 ((CompositeElement)root).subtreeChanged();
152 protected OuterLanguageElementImpl createOuterLanguageElement(final Lexer lexer, final CharTable table,
153 final IElementType outerElementType) {
154 final CharSequence buffer = lexer.getBufferSequence();
155 final int tokenStart = lexer.getTokenStart();
156 if (tokenStart < 0 || tokenStart > buffer.length()) {
157 LOG.assertTrue(false, "Invalid start: " + tokenStart + "; " + lexer);
159 final int tokenEnd = lexer.getTokenEnd();
160 if (tokenEnd < 0 || tokenEnd > buffer.length()) {
161 LOG.assertTrue(false, "Invalid end: " + tokenEnd + "; " + lexer);
164 return new OuterLanguageElementImpl(outerElementType, table.intern(buffer, tokenStart, tokenEnd));
167 private PsiFile createFromText(final Language language, CharSequence text, PsiManager manager) {
168 @NonNls
169 final LightVirtualFile virtualFile = new LightVirtualFile("foo", createTemplateFakeFileType(language), text, LocalTimeCounter.currentTime());
171 FileViewProvider viewProvider = new SingleRootFileViewProvider(manager, virtualFile, false) {
172 @NotNull
173 public Language getBaseLanguage() {
174 return language;
178 return viewProvider.getPsi(language);
181 protected static class TemplateFileType extends LanguageFileType {
182 private final Language myLanguage;
184 public TemplateFileType(final Language language) {
185 super(language);
186 myLanguage = language;
189 @NotNull
190 public String getDefaultExtension() {
191 return "";
194 @NotNull
195 @NonNls
196 public String getDescription() {
197 return "fake for language" + myLanguage.getID();
200 @Nullable
201 public Icon getIcon() {
202 return null;
205 @NotNull
206 @NonNls
207 public String getName() {
208 return myLanguage.getID();