diff options
Diffstat (limited to 'platform/lang-impl/src/com/intellij/psi')
3 files changed, 58 insertions, 150 deletions
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/search/LexerEditorHighlighterLexer.java b/platform/lang-impl/src/com/intellij/psi/impl/search/LexerEditorHighlighterLexer.java deleted file mode 100644 index 2add3ed1b3c5..000000000000 --- a/platform/lang-impl/src/com/intellij/psi/impl/search/LexerEditorHighlighterLexer.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2000-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.psi.impl.search; - -import com.intellij.lexer.Lexer; -import com.intellij.lexer.LexerBase; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.highlighter.EditorHighlighter; -import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; -import com.intellij.openapi.editor.highlighter.HighlighterIterator; -import com.intellij.openapi.editor.impl.EditorHighlighterCache; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; -import com.intellij.psi.impl.cache.impl.id.PlatformIdTableBuilding; -import com.intellij.psi.tree.IElementType; -import com.intellij.util.text.CharSequenceSubSequence; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** -* @author Sergey Evdokimov -*/ -public class LexerEditorHighlighterLexer extends LexerBase { - private HighlighterIterator iterator; - private CharSequence buffer; - private int start; - private int end; - private final EditorHighlighter myHighlighter; - private final boolean myAlreadyInitializedHighlighter; - - public LexerEditorHighlighterLexer(final EditorHighlighter highlighter, boolean alreadyInitializedHighlighter) { - myHighlighter = highlighter; - myAlreadyInitializedHighlighter = alreadyInitializedHighlighter; - } - - @Nullable - public static Lexer getLexerBasedOnLexerHighlighter(CharSequence text, VirtualFile virtualFile, Project project) { - EditorHighlighter highlighter = null; - - PsiFile psiFile = virtualFile != null ? PsiManager.getInstance(project).findFile(virtualFile) : null; - final Document document = psiFile != null ? PsiDocumentManager.getInstance(project).getDocument(psiFile) : null; - final EditorHighlighter cachedEditorHighlighter; - boolean alreadyInitializedHighlighter = false; - - if (document != null && - (cachedEditorHighlighter = EditorHighlighterCache.getEditorHighlighterForCachesBuilding(document)) != null && - PlatformIdTableBuilding.checkCanUseCachedEditorHighlighter(text, cachedEditorHighlighter)) { - highlighter = cachedEditorHighlighter; - alreadyInitializedHighlighter = true; - } - else if (virtualFile != null) { - highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(project, virtualFile); - } - - if (highlighter != null) { - return new LexerEditorHighlighterLexer(highlighter, alreadyInitializedHighlighter); - } - return null; - } - - @Override - public void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int state) { - if (myAlreadyInitializedHighlighter) { - this.buffer = buffer; - start = startOffset; - end = endOffset; - } else { - myHighlighter.setText(new CharSequenceSubSequence(this.buffer = buffer, start = startOffset, end = endOffset)); - } - iterator = myHighlighter.createIterator(0); - } - - public void resetPosition(int offset) { - iterator = myHighlighter.createIterator(offset); - } - - @Override - public int getState() { - return 0; - } - - @Override - public IElementType getTokenType() { - if (iterator.atEnd()) return null; - return iterator.getTokenType(); - } - - @Override - public int getTokenStart() { - return iterator.getStart(); - } - - @Override - public int getTokenEnd() { - return iterator.getEnd(); - } - - @Override - public void advance() { - iterator.advance(); - } - - @NotNull - @Override - public CharSequence getBufferSequence() { - return buffer; - } - - @Override - public int getBufferEnd() { - return end; - } - - public HighlighterIterator getHighlighterIterator() { - return iterator; - } -} diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerRunnable.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerRunnable.java index 1b17faf21905..42dcb46c7ac0 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerRunnable.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerRunnable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -149,7 +149,7 @@ abstract class CodeStyleManagerRunnable<T> { SourceTreeToPsiMap.psiElementToTree(CodeStyleManagerImpl.findElementInTreeWithFormatterEnabled(file, offset)); if (elementAtOffset == null) { int significantRangeStart = CharArrayUtil.shiftBackward(file.getText(), offset - 1, "\r\t "); - return new TextRange(significantRangeStart, offset); + return new TextRange(Math.max(significantRangeStart, 0), offset); } final FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(file); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java index 27089fa70e91..fdc434d8d11a 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java @@ -16,6 +16,7 @@ package com.intellij.psi.impl.source.tree.injected; +import com.intellij.extapi.psi.PsiFileBase; import com.intellij.injected.editor.*; import com.intellij.lang.Language; import com.intellij.lang.LanguageUtil; @@ -48,8 +49,10 @@ import java.util.List; * @author cdr */ public class InjectedLanguageUtil { - static final Key<List<Trinity<IElementType, SmartPsiElementPointer<PsiLanguageInjectionHost>, TextRange>>> HIGHLIGHT_TOKENS = Key.create("HIGHLIGHT_TOKENS"); - public static Key<Boolean> FRANKENSTEIN_INJECTION = Key.create("FRANKENSTEIN_INJECTION"); // meaning: injected file text is probably incorrect + static final Key<List<Trinity<IElementType, SmartPsiElementPointer<PsiLanguageInjectionHost>, TextRange>>> HIGHLIGHT_TOKENS = + Key.create("HIGHLIGHT_TOKENS"); + public static Key<Boolean> FRANKENSTEIN_INJECTION = Key.create("FRANKENSTEIN_INJECTION"); + // meaning: injected file text is probably incorrect public static void forceInjectionOnElement(@NotNull PsiElement host) { enumerate(host, new PsiLanguageInjectionHost.InjectedPsiVisitor() { @@ -113,9 +116,9 @@ public class InjectedLanguageUtil { * @return true if enumerated successfully */ public static boolean enumerate(@NotNull PsiElement host, - @NotNull PsiFile containingFile, - boolean probeUp, - @NotNull PsiLanguageInjectionHost.InjectedPsiVisitor visitor) { + @NotNull PsiFile containingFile, + boolean probeUp, + @NotNull PsiLanguageInjectionHost.InjectedPsiVisitor visitor) { //do not inject into nonphysical files except during completion if (!containingFile.isPhysical() && containingFile.getOriginalFile() == containingFile) { final PsiElement context = InjectedLanguageManager.getInstance(containingFile.getProject()).getInjectionHost(containingFile); @@ -175,6 +178,32 @@ public class InjectedLanguageUtil { return null; } + /** + * Finds injected language in expression + * + * @param expression where to find + * @param classToFind class that represents language we look for + * @param <T> class that represents language we look for + * @return instance of class that represents language we look for or null of not found + */ + @Nullable + @SuppressWarnings("unchecked") // We check types dynamically (using isAssignableFrom) + public static <T extends PsiFileBase> T findInjectedFile(@NotNull final PsiElement expression, + @NotNull final Class<T> classToFind) { + final List<Pair<PsiElement, TextRange>> files = + InjectedLanguageManager.getInstance(expression.getProject()).getInjectedPsiFiles(expression); + if (files == null) { + return null; + } + for (final Pair<PsiElement, TextRange> fileInfo : files) { + final PsiElement injectedFile = fileInfo.first; + if (classToFind.isAssignableFrom(injectedFile.getClass())) { + return (T)injectedFile; + } + } + return null; + } + public static Editor getEditorForInjectedLanguageNoCommit(@Nullable Editor editor, @Nullable PsiFile file, final int offset) { if (editor == null || file == null || editor instanceof EditorWindow) return editor; PsiFile injectedFile = findInjectedPsiNoCommit(file, offset); @@ -200,7 +229,9 @@ public class InjectedLanguageUtil { } } } - if (!documentWindow.isValid()) return hostEditor; // since the moment we got hold of injectedFile and this moment call, document may have been dirtied + if (!documentWindow.isValid()) { + return hostEditor; // since the moment we got hold of injectedFile and this moment call, document may have been dirtied + } return EditorWindowImpl.create(documentWindow, (EditorImpl)hostEditor, injectedFile); } @@ -284,7 +315,8 @@ public class InjectedLanguageUtil { ParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement> cachedValue = CachedValuesManager.getManager(project).createParameterizedCachedValue(INJECTED_PSI_PROVIDER, false); - CachedValueProvider.Result<MultiHostRegistrarImpl> result = CachedValueProvider.Result.create(registrar, PsiModificationTracker.MODIFICATION_COUNT, registrar); + CachedValueProvider.Result<MultiHostRegistrarImpl> result = + CachedValueProvider.Result.create(registrar, PsiModificationTracker.MODIFICATION_COUNT, registrar); ((PsiParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement>)cachedValue).setValue(result); e.putUserData(INJECTED_PSI, cachedValue); @@ -307,7 +339,9 @@ public class InjectedLanguageUtil { // returns (injected psi, leaf element at the offset, language of the leaf element) // since findElementAt() is expensive, we trying to reuse its result @NotNull - private static Trinity<PsiElement,PsiElement,Language> tryOffset(@NotNull PsiFile hostFile, final int offset, @NotNull PsiDocumentManager documentManager) { + private static Trinity<PsiElement, PsiElement, Language> tryOffset(@NotNull PsiFile hostFile, + final int offset, + @NotNull PsiDocumentManager documentManager) { FileViewProvider provider = hostFile.getViewProvider(); Language leafLanguage = null; PsiElement leafElement = null; @@ -319,11 +353,11 @@ public class InjectedLanguageUtil { leafElement = element; } PsiElement injected = findInside(element, hostFile, offset, documentManager); - if (injected != null) return Trinity.create(injected,element, language); + if (injected != null) return Trinity.create(injected, element, language); } // maybe we are at the border between two psi elements, then try to find injection at the end of the left element if (offset != 0 && (element == null || element.getTextRange().getStartOffset() == offset)) { - PsiElement leftElement = provider.findElementAt(offset-1, language); + PsiElement leftElement = provider.findElementAt(offset - 1, language); if (leftElement != null && leftElement.getTextRange().getEndOffset() == offset) { PsiElement injected = findInside(leftElement, hostFile, offset, documentManager); if (injected != null) return Trinity.create(injected, element, language); @@ -334,7 +368,10 @@ public class InjectedLanguageUtil { return Trinity.create(null, leafElement, leafLanguage); } - private static PsiElement findInside(@NotNull PsiElement element, @NotNull PsiFile hostFile, final int hostOffset, @NotNull final PsiDocumentManager documentManager) { + private static PsiElement findInside(@NotNull PsiElement element, + @NotNull PsiFile hostFile, + final int hostOffset, + @NotNull final PsiDocumentManager documentManager) { final Ref<PsiElement> out = new Ref<PsiElement>(); enumerate(element, hostFile, true, new PsiLanguageInjectionHost.InjectedPsiVisitor() { @Override @@ -361,10 +398,12 @@ public class InjectedLanguageUtil { // modification of cachedInjectedDocuments must be under PsiLock only ConcurrentList<DocumentWindow> injected = hostPsiFile.getUserData(INJECTED_DOCS_KEY); if (injected == null) { - injected = ((UserDataHolderEx)hostPsiFile).putUserDataIfAbsent(INJECTED_DOCS_KEY, ContainerUtil.<DocumentWindow>createConcurrentList()); + injected = + ((UserDataHolderEx)hostPsiFile).putUserDataIfAbsent(INJECTED_DOCS_KEY, ContainerUtil.<DocumentWindow>createConcurrentList()); } return injected; } + public static void clearCachedInjectedFragmentsForFile(@NotNull PsiFile file) { file.putUserData(INJECTED_DOCS_KEY, null); } @@ -426,10 +465,12 @@ public class InjectedLanguageUtil { } return containingFile; } + @NotNull public static Editor getTopLevelEditor(@NotNull Editor editor) { return editor instanceof EditorWindow ? ((EditorWindow)editor).getDelegate() : editor; } + public static boolean isInInjectedLanguagePrefixSuffix(@NotNull final PsiElement element) { PsiFile injectedFile = element.getContainingFile(); if (injectedFile == null) return false; @@ -461,13 +502,13 @@ public class InjectedLanguageUtil { public static String getUnescapedText(PsiFile file, @Nullable final PsiElement startElement, @Nullable final PsiElement endElement) { final InjectedLanguageManager manager = InjectedLanguageManager.getInstance(file.getProject()); if (manager.getInjectionHost(file) == null) { - return file.getText().substring(startElement == null? 0 : startElement.getTextRange().getStartOffset(), - endElement == null? file.getTextLength() : endElement.getTextRange().getStartOffset()); + return file.getText().substring(startElement == null ? 0 : startElement.getTextRange().getStartOffset(), + endElement == null ? file.getTextLength() : endElement.getTextRange().getStartOffset()); } final StringBuilder sb = new StringBuilder(); file.accept(new PsiRecursiveElementWalkingVisitor() { - Boolean myState = startElement == null? Boolean.TRUE : null; + Boolean myState = startElement == null ? Boolean.TRUE : null; @Override public void visitElement(PsiElement element) { |