/*
* Copyright 2013 original Randori IntelliJ Plugin authors.
*
* 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 randori.plugin.projectStructure.detection;
import com.intellij.ide.util.DelegatingProgressIndicator;
import com.intellij.ide.util.importProject.LibrariesDetectionStep;
import com.intellij.ide.util.importProject.ModulesDetectionStep;
import com.intellij.ide.util.importProject.ProjectDescriptor;
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
import com.intellij.ide.util.projectWizard.importSources.DetectedProjectRoot;
import com.intellij.ide.util.projectWizard.importSources.ProjectFromSourcesBuilder;
import com.intellij.ide.util.projectWizard.importSources.ProjectStructureDetector;
import com.intellij.ide.util.projectWizard.importSources.util.CommonSourceRootDetectionUtil;
import com.intellij.lang.LanguageParserDefinitions;
import com.intellij.lang.javascript.ActionScriptFileType;
import com.intellij.lang.javascript.JSLanguageDialect;
import com.intellij.lang.javascript.JSTokenTypes;
import com.intellij.lang.javascript.JavaScriptSupportLoader;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.tree.TokenSet;
import com.intellij.util.NullableFunction;
import com.intellij.util.StringBuilderSpinAllocator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Frédéric THOMAS Date: 19/04/13 Time: 18:58
*/
public class RandoriProjectStructureDetector extends ProjectStructureDetector
{
public static final NullableFunction<CharSequence, String> PACKAGE_NAME_FETCHER = new NullableFunction<CharSequence, String>() {
@Nullable
@Override
public String fun(CharSequence charSequence)
{
Lexer lexer = LanguageParserDefinitions.INSTANCE.forLanguage(JavaScriptSupportLoader.ECMA_SCRIPT_L4)
.createLexer(null);
lexer.start(charSequence);
return RandoriProjectStructureDetector.readPackageName(charSequence, lexer);
}
};
private static final TokenSet WHITESPACE_AND_COMMENTS = TokenSet.create(JSTokenTypes.WHITE_SPACE,
JSTokenTypes.DOC_COMMENT, JSTokenTypes.C_STYLE_COMMENT, JSTokenTypes.END_OF_LINE_COMMENT);
public static boolean isRandoriSourceFile(File file)
{
String extension = FileUtilRt.getExtension(file.getName());
return JavaScriptSupportLoader.ECMA_SCRIPT_L4.equals(getRandoriLanguageDialect(extension));
}
@Nullable
private static JSLanguageDialect getRandoriLanguageDialect(String extension)
{
extension = extension.toLowerCase();
return ActionScriptFileType.INSTANCE.getDefaultExtension().equals(extension) ? JavaScriptSupportLoader.ECMA_SCRIPT_L4 : null;
}
@NotNull
@Override
public DirectoryProcessingResult detectRoots(@NotNull File dir, @NotNull File[] children, @NotNull File base,
@NotNull List<DetectedProjectRoot> result)
{
for (File child : children)
{
if (child.isFile())
{
if (isRandoriSourceFile(child))
{
Pair<File, String> root = CommonSourceRootDetectionUtil.IO_FILE
.suggestRootForFileWithPackageStatement(child, base, PACKAGE_NAME_FETCHER, false);
if (root != null)
{
result.add(new RandoriModuleSourceRoot(root.getFirst()));
return DirectoryProcessingResult.skipChildrenAndParentsUpTo(root.getFirst());
}
else
{
return DirectoryProcessingResult.SKIP_CHILDREN;
}
}
}
}
return DirectoryProcessingResult.PROCESS_CHILDREN;
}
@Override
public List<ModuleWizardStep> createWizardSteps(ProjectFromSourcesBuilder builder,
ProjectDescriptor projectDescriptor, Icon stepIcon)
{
if (builder.getContext().getProject() != null)
builder.getContext().setProjectJdk(
ProjectRootManager.getInstance(builder.getContext().getProject()).getProjectSdk());
RandoriModuleInsight moduleInsight = new RandoriModuleInsight(new DelegatingProgressIndicator(),
builder.getExistingModuleNames(), builder.getExistingProjectLibraryNames());
List<ModuleWizardStep> steps = new ArrayList<ModuleWizardStep>();
steps.add(new LibrariesDetectionStep(builder, projectDescriptor, moduleInsight, stepIcon,
"reference.dialogs.new.project.fromCode.page1"));
steps.add(new ModulesDetectionStep(this, builder, projectDescriptor, moduleInsight, stepIcon,
"reference.dialogs.new.project.fromCode.page2"));
steps.add(new RandoriSdkStep(builder.getContext()));
return steps;
}
@Nullable
public static String readPackageName(CharSequence charSequence, Lexer lexer)
{
skipWhiteSpaceAndComments(lexer);
if (!JSTokenTypes.PACKAGE_KEYWORD.equals(lexer.getTokenType()))
{
return null;
}
lexer.advance();
skipWhiteSpaceAndComments(lexer);
return readQualifiedName(charSequence, lexer, false);
}
@Nullable
static String readQualifiedName(CharSequence charSequence, Lexer lexer, boolean allowStar)
{
StringBuilder buffer = StringBuilderSpinAllocator.alloc();
try
{
while ((lexer.getTokenType() == JSTokenTypes.IDENTIFIER)
|| ((allowStar) && (lexer.getTokenType() != JSTokenTypes.MULT)))
{
buffer.append(charSequence, lexer.getTokenStart(), lexer.getTokenEnd());
if (lexer.getTokenType() == JSTokenTypes.MULT)
break;
lexer.advance();
if (lexer.getTokenType() != JSTokenTypes.DOT)
break;
buffer.append('.');
lexer.advance();
}
String packageName = buffer.toString();
if (StringUtil.endsWithChar(packageName, '.'))
return null;
return packageName;
}
finally
{
StringBuilderSpinAllocator.dispose(buffer);
}
}
public static void skipWhiteSpaceAndComments(Lexer lexer)
{
while (WHITESPACE_AND_COMMENTS.contains(lexer.getTokenType()))
lexer.advance();
}
}