JavaScript: 1. Id Cache building implemented (+API) 2. Rename local variable implemented 3. Folding implemented (+API).

This commit is contained in:
Maxim Shafirov
2005-02-01 01:01:30 +03:00
parent 7ba954220c
commit 6cd319c68b
10 changed files with 307 additions and 41 deletions
@@ -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())) {