mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
JavaScript: 1. Id Cache building implemented (+API) 2. Rename local variable implemented 3. Folding implemented (+API).
This commit is contained in:
@@ -45,7 +45,8 @@ public class ASTWrapperPsiElement extends ElementBase implements PsiElement, Nav
|
||||
}
|
||||
|
||||
public PsiManager getManager() {
|
||||
return getParent().getManager();
|
||||
final PsiElement parent = getParent();
|
||||
return parent != null ? parent.getManager() : null;
|
||||
}
|
||||
|
||||
public PsiElement[] getChildren() {
|
||||
@@ -235,7 +236,7 @@ public class ASTWrapperPsiElement extends ElementBase implements PsiElement, Nav
|
||||
}
|
||||
|
||||
public SearchScope getUseScope() {
|
||||
throw new UnsupportedOperationException();
|
||||
return getManager().getSearchHelper().getUseScope(this);
|
||||
}
|
||||
|
||||
public ItemPresentation getPresentation() {
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.intellij.lang;
|
||||
|
||||
import com.intellij.codeFormatting.PseudoTextBuilder;
|
||||
import com.intellij.lang.cacheBuilder.WordsScanner;
|
||||
import com.intellij.lang.folding.FoldingBuilder;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.PlainSyntaxHighlighter;
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -47,6 +50,18 @@ public abstract class Language {
|
||||
return null;
|
||||
}
|
||||
|
||||
public WordsScanner getWordsScanner() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean mayHaveReferences(IElementType token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public FoldingBuilder getFoldingBuilder() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Language: " + myID;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.intellij.lang.cacheBuilder;
|
||||
|
||||
import com.intellij.lexer.Lexer;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.text.CharArrayCharSequence;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: max
|
||||
* Date: Jan 31, 2005
|
||||
* Time: 9:12:33 PM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class DefaultWordsScanner implements WordsScanner {
|
||||
private Lexer myLexer;
|
||||
private TokenSet myIdentifierTokenSet;
|
||||
private TokenSet myCommentTokenSet;
|
||||
private TokenSet myLiteralTokenSet;
|
||||
|
||||
public DefaultWordsScanner(final Lexer lexer, final TokenSet identifierTokenSet, final TokenSet commentTokenSet, final TokenSet literalTokenSet) {
|
||||
myLexer = lexer;
|
||||
myIdentifierTokenSet = identifierTokenSet;
|
||||
myCommentTokenSet = commentTokenSet;
|
||||
myLiteralTokenSet = literalTokenSet;
|
||||
}
|
||||
|
||||
public void processWords(CharSequence fileText, Processor<WordOccurence> processor) {
|
||||
char[] chars = CharArrayUtil.fromSequence(fileText);
|
||||
myLexer.start(chars, 0, fileText.length());
|
||||
while (myLexer.getTokenType() != null) {
|
||||
final IElementType type = myLexer.getTokenType();
|
||||
if (myIdentifierTokenSet.isInSet(type)) {
|
||||
if (!processor.process(new WordOccurence(currentTokenText(chars), WordOccurence.Kind.CODE))) return;
|
||||
}
|
||||
else if (myCommentTokenSet.isInSet(type)) {
|
||||
if (!stripWords(processor, currentTokenText(chars), WordOccurence.Kind.COMMENTS)) return;
|
||||
}
|
||||
else if (myLiteralTokenSet.isInSet(type)) {
|
||||
if (!stripWords(processor, currentTokenText(chars), WordOccurence.Kind.LITERALS)) return;
|
||||
}
|
||||
myLexer.advance();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This code seems strange but it is more effective as Character.isJavaIdentifier_xxx_ quite hard operation due to unicode
|
||||
*/
|
||||
private static boolean stripWords(final Processor<WordOccurence> processor,
|
||||
final CharArrayCharSequence tokenText,
|
||||
final WordOccurence.Kind kind) {
|
||||
int index = 0;
|
||||
|
||||
ScanWordsLoop:
|
||||
while(true){
|
||||
while(true){
|
||||
if (index == tokenText.length()) break ScanWordsLoop;
|
||||
char c = tokenText.charAt(index);
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (Character.isJavaIdentifierStart(c) && c != '$')) break;
|
||||
index++;
|
||||
}
|
||||
int index1 = index;
|
||||
while(true){
|
||||
index++;
|
||||
if (index == tokenText.length()) break;
|
||||
char c = tokenText.charAt(index);
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) continue;
|
||||
if (!Character.isJavaIdentifierPart(c) || c == '$') break;
|
||||
}
|
||||
if (index - index1 > 100) continue; // Strange limit but we should have some!
|
||||
|
||||
if (!processor.process(new WordOccurence(tokenText.subSequence(index1, index), kind))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private CharArrayCharSequence currentTokenText(final char[] chars) {
|
||||
return new CharArrayCharSequence(chars, myLexer.getTokenStart(), myLexer.getTokenEnd());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.intellij.lang.cacheBuilder;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: max
|
||||
* Date: Jan 31, 2005
|
||||
* Time: 9:09:06 PM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class WordOccurence {
|
||||
private Kind myKind;
|
||||
private CharSequence myText;
|
||||
|
||||
public WordOccurence(final CharSequence text, final Kind kind) {
|
||||
myKind = kind;
|
||||
myText = text;
|
||||
}
|
||||
|
||||
public Kind getKind() {
|
||||
return myKind;
|
||||
}
|
||||
|
||||
public CharSequence getText() {
|
||||
return myText;
|
||||
}
|
||||
|
||||
public static class Kind {
|
||||
public static final Kind CODE = new Kind("CODE");
|
||||
public static final Kind COMMENTS = new Kind("COMMENTS");
|
||||
public static final Kind LITERALS = new Kind("LITERALS");
|
||||
|
||||
private String myName;
|
||||
|
||||
private Kind(String name){
|
||||
myName = name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "WordOccurence.Kind(" + myName + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.intellij.lang.cacheBuilder;
|
||||
|
||||
import com.intellij.util.Processor;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: max
|
||||
* Date: Jan 31, 2005
|
||||
* Time: 9:07:44 PM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public interface WordsScanner {
|
||||
void processWords(CharSequence fileText, Processor<WordOccurence> processor);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.intellij.lang.folding;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: max
|
||||
* Date: Feb 1, 2005
|
||||
* Time: 12:10:19 AM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public interface FoldingBuilder {
|
||||
FoldingDescriptor[] buildFoldRegions(PsiElement file, Document document);
|
||||
|
||||
String getPlaceholderText(PsiElement elt);
|
||||
|
||||
boolean isCollapsedByDefault(PsiElement elt);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.intellij.lang.folding;
|
||||
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: max
|
||||
* Date: Feb 1, 2005
|
||||
* Time: 12:14:17 AM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class FoldingDescriptor {
|
||||
private PsiElement myElement;
|
||||
private TextRange myRange;
|
||||
|
||||
public FoldingDescriptor(final PsiElement element, final TextRange range) {
|
||||
myElement = element;
|
||||
myRange = range;
|
||||
}
|
||||
|
||||
public PsiElement getElement() {
|
||||
return myElement;
|
||||
}
|
||||
|
||||
public TextRange getRange() {
|
||||
return myRange;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
package com.intellij.codeInsight.folding.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.folding.FoldingBuilder;
|
||||
import com.intellij.lang.folding.FoldingDescriptor;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
@@ -10,7 +14,6 @@ import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import com.intellij.psi.util.PropertyUtil;
|
||||
import com.intellij.psi.xml.*;
|
||||
import com.intellij.uiDesigner.compiler.CodeGenerator;
|
||||
import com.intellij.lang.ASTNode;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -28,6 +31,18 @@ class FoldingPolicy {
|
||||
element1.getTextRange().getEndOffset() - element.getTextRange().getEndOffset();
|
||||
}
|
||||
});
|
||||
final Language lang = file.getLanguage();
|
||||
if (lang != null) {
|
||||
final FoldingBuilder foldingBuilder = lang.getFoldingBuilder();
|
||||
if (foldingBuilder != null) {
|
||||
final FoldingDescriptor[] foldingDescriptors = foldingBuilder.buildFoldRegions(file, document);
|
||||
for (int i = 0; i < foldingDescriptors.length; i++) {
|
||||
FoldingDescriptor descriptor = foldingDescriptors[i];
|
||||
map.put(descriptor.getElement(), descriptor.getRange());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
if (file instanceof PsiJavaFile) {
|
||||
PsiImportList importList = ((PsiJavaFile) file).getImportList();
|
||||
@@ -242,6 +257,14 @@ class FoldingPolicy {
|
||||
}
|
||||
|
||||
public static String getFoldingText(PsiElement element) {
|
||||
final Language lang = element.getLanguage();
|
||||
if (lang != null) {
|
||||
final FoldingBuilder foldingBuilder = lang.getFoldingBuilder();
|
||||
if (foldingBuilder != null) {
|
||||
return foldingBuilder.getPlaceholderText(element);
|
||||
}
|
||||
}
|
||||
|
||||
if (element instanceof PsiImportList) {
|
||||
return "...";
|
||||
} else if ( element instanceof PsiMethod && CodeGenerator.SETUP_METHOD_NAME.equals(((PsiMethod) element).getName()) ||
|
||||
@@ -264,6 +287,14 @@ class FoldingPolicy {
|
||||
|
||||
|
||||
public static boolean isCollapseByDefault(PsiElement element) {
|
||||
final Language lang = element.getLanguage();
|
||||
if (lang != null) {
|
||||
final FoldingBuilder foldingBuilder = lang.getFoldingBuilder();
|
||||
if (foldingBuilder != null) {
|
||||
return foldingBuilder.isCollapsedByDefault(element);
|
||||
}
|
||||
}
|
||||
|
||||
CodeFoldingSettings settings = CodeFoldingSettings.getInstance();
|
||||
if (element instanceof PsiImportList) {
|
||||
return settings.COLLAPSE_IMPORTS;
|
||||
|
||||
@@ -4,6 +4,9 @@ import com.intellij.aspects.lexer._AspectjLexer;
|
||||
import com.intellij.aspects.psi.PsiAspectFile;
|
||||
import com.intellij.ide.startup.FileContent;
|
||||
import com.intellij.ide.todo.TodoConfiguration;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.cacheBuilder.WordOccurence;
|
||||
import com.intellij.lang.cacheBuilder.WordsScanner;
|
||||
import com.intellij.lexer.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
@@ -11,7 +14,6 @@ import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.impl.PsiManagerImpl;
|
||||
import com.intellij.psi.impl.cache.impl.CacheManagerImpl;
|
||||
import com.intellij.psi.impl.source.parsing.jsp.JspStep1Lexer;
|
||||
@@ -21,16 +23,18 @@ import com.intellij.psi.jsp.JspFile;
|
||||
import com.intellij.psi.search.TodoPattern;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.java.IJavaElementType;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.uiDesigner.FormEditingUtil;
|
||||
import com.intellij.uiDesigner.compiler.Utils;
|
||||
import com.intellij.uiDesigner.lw.IComponent;
|
||||
import com.intellij.uiDesigner.lw.LwRootContainer;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.text.CharArrayCharSequence;
|
||||
import gnu.trove.TIntIntHashMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class IdTableBuilding {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.cache.impl.idCache.IdTableBuilding");
|
||||
@@ -217,9 +221,41 @@ public class IdTableBuilding {
|
||||
return cacheBuilders.get(StdFileTypes.XML);
|
||||
}
|
||||
|
||||
final Language lang = psiFile.getLanguage();
|
||||
if (lang != null) {
|
||||
final WordsScanner scanner = lang.getWordsScanner();
|
||||
if (scanner != null) {
|
||||
return new WordsScannerIdCacheBuilderAdapter(scanner);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class WordsScannerIdCacheBuilderAdapter implements IdCacheBuilder {
|
||||
private WordsScanner myScanner;
|
||||
|
||||
public WordsScannerIdCacheBuilderAdapter(final WordsScanner scanner) {
|
||||
myScanner = scanner;
|
||||
}
|
||||
|
||||
public void build(char[] chars, int length, final TIntIntHashMap wordsTable, TodoPattern[] todoPatterns, int[] todoCounts) {
|
||||
myScanner.processWords(new CharArrayCharSequence(chars, 0, length), new Processor<WordOccurence>() {
|
||||
public boolean process(final WordOccurence t) {
|
||||
IdCacheUtil.addOccurrence(wordsTable, t.getText().toString().hashCode(), convertToMask(t.getKind()));
|
||||
return true;
|
||||
}
|
||||
|
||||
private int convertToMask(final WordOccurence.Kind kind) {
|
||||
if (kind == WordOccurence.Kind.CODE) return WordInfo.IN_CODE;
|
||||
if (kind == WordOccurence.Kind.COMMENTS) return WordInfo.IN_COMMENTS;
|
||||
if (kind == WordOccurence.Kind.LITERALS) return WordInfo.IN_STRING_LITERALS;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static Result getBuildingRunnable(PsiManagerImpl manager, FileContent fileContent, final boolean buildTodos) {
|
||||
if (LOG.isDebugEnabled()){
|
||||
LOG.debug(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.intellij.psi.impl.search;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -9,11 +10,9 @@ import com.intellij.psi.impl.source.parsing.ChameleonTransforming;
|
||||
import com.intellij.psi.impl.source.tree.ChameleonElement;
|
||||
import com.intellij.psi.impl.source.tree.CompositeElement;
|
||||
import com.intellij.psi.impl.source.tree.LeafElement;
|
||||
import com.intellij.psi.impl.source.tree.TreeElement;
|
||||
import com.intellij.psi.search.PsiElementProcessor;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.util.text.StringSearcher;
|
||||
import com.intellij.lang.ASTNode;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@@ -33,8 +32,8 @@ public class LowLevelSearchUtil {
|
||||
TokenSet elementTypes,
|
||||
ProgressIndicator progress) {
|
||||
ProgressManager.getInstance().checkCanceled();
|
||||
|
||||
if (elementTypes.isInSet(scope.getElementType())) {
|
||||
final PsiElement scopePsi = SourceTreeToPsiMap.treeElementToPsi(scope);
|
||||
if (elementTypes.isInSet(scope.getElementType()) || scopePsi.getLanguage() != null && scopePsi.getLanguage().mayHaveReferences(scope.getElementType())) {
|
||||
int startOffset;
|
||||
int endOffset;
|
||||
if (scope instanceof LeafElement) {
|
||||
@@ -44,7 +43,7 @@ public class LowLevelSearchUtil {
|
||||
do {
|
||||
int i = leaf.searchWord(startOffset, searcher);
|
||||
if (i >= 0) {
|
||||
if (!processor.execute(SourceTreeToPsiMap.treeElementToPsi(scope), i)) return false;
|
||||
if (!processor.execute(scopePsi, i)) return false;
|
||||
startOffset = i + 1;
|
||||
}
|
||||
else {
|
||||
@@ -76,7 +75,7 @@ public class LowLevelSearchUtil {
|
||||
do {
|
||||
int i = searchWord(buffer, startOffset, endOffset, searcher);
|
||||
if (i >= 0) {
|
||||
if (!processor.execute(SourceTreeToPsiMap.treeElementToPsi(scope), i - originalStartOffset)) return false;
|
||||
if (!processor.execute(scopePsi, i - originalStartOffset)) return false;
|
||||
startOffset = i + 1;
|
||||
}
|
||||
else {
|
||||
@@ -99,40 +98,39 @@ public class LowLevelSearchUtil {
|
||||
PsiElementProcessorEx processor,
|
||||
TokenSet elementTypes,
|
||||
ProgressIndicator progress) {
|
||||
synchronized (PsiLock.LOCK) {
|
||||
ASTNode child = scope.getFirstChildNode();
|
||||
while (child != null) {
|
||||
if (child instanceof ChameleonElement) {
|
||||
LeafElement leaf = (LeafElement)child;
|
||||
if (leaf.searchWord(0, searcher) >= 0) {
|
||||
ASTNode next = child.getTreeNext();
|
||||
child = ChameleonTransforming.transform((ChameleonElement)child);
|
||||
if (child == null) {
|
||||
child = next;
|
||||
synchronized (PsiLock.LOCK) {
|
||||
ASTNode child = scope.getFirstChildNode();
|
||||
while (child != null) {
|
||||
if (child instanceof ChameleonElement) {
|
||||
LeafElement leaf = (LeafElement)child;
|
||||
if (leaf.searchWord(0, searcher) >= 0) {
|
||||
ASTNode next = child.getTreeNext();
|
||||
child = ChameleonTransforming.transform((ChameleonElement)child);
|
||||
if (child == null) {
|
||||
child = next;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
child = child.getTreeNext();
|
||||
}
|
||||
child = child.getTreeNext();
|
||||
}
|
||||
}
|
||||
|
||||
ASTNode child = null;
|
||||
while (true) {
|
||||
synchronized (PsiLock.LOCK) {
|
||||
child = child != null ? child.getTreeNext() : scope.getFirstChildNode();
|
||||
while (child instanceof ChameleonElement) {
|
||||
child = child.getTreeNext();
|
||||
}
|
||||
if (child == null) break;
|
||||
}
|
||||
ASTNode child = null;
|
||||
while (true) {
|
||||
synchronized (PsiLock.LOCK) {
|
||||
child = child != null ? child.getTreeNext() : scope.getFirstChildNode();
|
||||
while (child instanceof ChameleonElement) {
|
||||
child = child.getTreeNext();
|
||||
}
|
||||
if (child == null) break;
|
||||
}
|
||||
|
||||
if (!processElementsContainingWordInElement(processor, (TreeElement)child, searcher, elementTypes,
|
||||
progress)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
if (!processElementsContainingWordInElement(processor, child, searcher, elementTypes, progress)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int searchWord(char[] text, int startOffset, int endOffset, StringSearcher searcher) {
|
||||
@@ -164,8 +162,7 @@ public class LowLevelSearchUtil {
|
||||
ASTNode scope,
|
||||
TokenSet elementTypes,
|
||||
Set namesSet,
|
||||
ProgressIndicator progress
|
||||
) {
|
||||
ProgressIndicator progress) {
|
||||
ProgressManager.getInstance().checkCanceled();
|
||||
|
||||
if (elementTypes.isInSet(scope.getElementType())) {
|
||||
|
||||
Reference in New Issue
Block a user