JS IDE: Replace indication file with module component

Introduce K2JSModuleComponent
Partially replace references to project with references to module (Should be able to tell which facade to use based on what module we are in)
#KT-2064 fixed
This commit is contained in:
pTalanov
2012-06-04 21:11:39 +04:00
parent d55d2c7bcf
commit 4f89d8be3e
11 changed files with 222 additions and 113 deletions
+6
View File
@@ -29,6 +29,12 @@
</component>
</project-components>
<module-components>
<component>
<implementation-class>org.jetbrains.jet.plugin.project.K2JSModuleComponent</implementation-class>
</component>
</module-components>
<actions>
<action id="Kotlin.NewFile" class="org.jetbrains.jet.plugin.actions.NewKotlinFileAction">
<add-to-group group-id="NewGroup" anchor="before" relative-to-action="NewFromTemplate"/>
@@ -26,7 +26,6 @@ import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.TranslatingCompiler;
import com.intellij.openapi.compiler.ex.CompileContextEx;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkType;
import com.intellij.openapi.projectRoots.JdkUtil;
import com.intellij.openapi.projectRoots.Sdk;
@@ -61,8 +60,8 @@ public class JetCompiler implements TranslatingCompiler {
if (!(virtualFile.getFileType() instanceof JetFileType)) {
return false;
}
Project project = compileContext.getProject();
if (project != null && JsModuleDetector.isJsProject(project)) {
Module module = compileContext.getModuleByFile(virtualFile);
if (module != null && JsModuleDetector.isJsModule(module)) {
return false;
}
return true;
@@ -51,11 +51,11 @@ public final class K2JSCompiler implements TranslatingCompiler {
if (!(file.getFileType() instanceof JetFileType)) {
return false;
}
Project project = context.getProject();
if (project == null) {
Module module = context.getModuleByFile(file);
if (module == null) {
return false;
}
return JsModuleDetector.isJsProject(project);
return JsModuleDetector.isJsModule(module);
}
@Override
@@ -142,14 +142,14 @@ public final class K2JSCompiler implements TranslatingCompiler {
}
private static void addLibLocationAndTarget(@NotNull Project project, @NotNull ArrayList<String> args) {
Pair<String, String> data = JsModuleDetector.getLibLocationAndTargetForProject(project);
if (data.first != null) {
Pair<String, String> libLocationAndTarget = JsModuleDetector.getLibLocationAndTargetForProject(project);
if (libLocationAndTarget.first != null) {
args.add("-libzip");
args.add(data.first);
args.add(libLocationAndTarget.first);
}
if (data.second != null) {
if (libLocationAndTarget.second != null) {
args.add("-target");
args.add(data.second);
args.add(libLocationAndTarget.second);
}
}
@@ -69,6 +69,7 @@ public final class K2JSRunnerUtils {
@NotNull
public static Module getJsModule(@NotNull Project project) {
//TODO Should not be there, we should know what module we are in
Module[] modules = ModuleManager.getInstance(project).getModules();
if (modules.length != 1) {
throw new UnsupportedOperationException("Kotlin to JavaScript translator temporarily does not support multiple modules.");
@@ -71,7 +71,7 @@ public class JetSourceNavigationHelper {
}
final Project project = declaration.getProject();
final List<JetFile> libraryFiles = findAllSourceFilesWhichContainIdentifier(declaration);
BindingContext bindingContext = AnalyzerFacadeProvider.getAnalyzerFacadeForProject(project).analyzeFiles(
BindingContext bindingContext = AnalyzerFacadeProvider.getAnalyzerFacadeForProject().analyzeFiles(
project,
libraryFiles,
Collections.<AnalyzerScriptParameter>emptyList(),
@@ -16,31 +16,64 @@
package org.jetbrains.jet.plugin.project;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.analyzer.AnalyzerFacade;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
import org.jetbrains.k2js.analyze.AnalyzerFacadeForJS;
/**
* @author Pavel Talanov
*/
public final class AnalyzerFacadeProvider {
private final static Logger LOG = Logger.getInstance(AnalyzerFacade.class);
private AnalyzerFacadeProvider() {
}
@NotNull
public static AnalyzerFacade getAnalyzerFacadeForFile(@NotNull JetFile file) {
return getAnalyzerFacadeForProject(file.getProject());
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null) {
logErrorIfNotTests("No virtual file for " + file.getName() + " with text:\n" + file.getText());
return getDefaultAnalyzerFacade();
}
Module moduleForFile = ProjectFileIndex.SERVICE.getInstance(file.getProject()).getModuleForFile(virtualFile);
if (moduleForFile == null) {
logErrorIfNotTests("File " + virtualFile.getPath() + " is not under any module. Cannot determine which facade to use.");
return getDefaultAnalyzerFacade();
}
return getAnalyzerFacadeForModule(moduleForFile);
}
private static void logErrorIfNotTests(@NotNull String message) {
if (!ApplicationManager.getApplication().isUnitTestMode()) {
LOG.error(message);
}
}
@NotNull
public static AnalyzerFacade getAnalyzerFacadeForProject(@NotNull Project project) {
if (JsModuleDetector.isJsProject(project)) {
private static AnalyzerFacade getDefaultAnalyzerFacade() {
LOG.info("Using default analyzer facade");
return AnalyzerFacadeForJVM.INSTANCE;
}
@NotNull
private static AnalyzerFacade getAnalyzerFacadeForModule(@NotNull Module module) {
if (JsModuleDetector.isJsModule(module)) {
return JSAnalyzerFacadeForIDEA.INSTANCE;
}
return AnalyzerFacadeForJVM.INSTANCE;
}
//TODO should remove all calls to this method
@NotNull
public static AnalyzerFacade getAnalyzerFacadeForProject() {
return AnalyzerFacadeForJVM.INSTANCE;
}
}
@@ -16,77 +16,47 @@
package org.jetbrains.jet.plugin.project;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
/**
* @author Pavel Talanov
* <p/>
* This class has utility functions to determine whether the project (or module) is js project.
*/
public final class JsModuleDetector {
public static final String INDICATION_FILE_NAME = ".kotlin-js";
private JsModuleDetector() {
}
public static boolean isJsProject(@NotNull Project project) {
return findIndicationFileInContentRoots(project) != null;
public static boolean isJsModule(@NotNull Module module) {
return K2JSModuleComponent.getInstance(module).isJavaScriptModule();
}
@NotNull
public static Pair<String, String> getLibLocationAndTargetForProject(@NotNull Project project) {
Module module = getJSModule(project);
if (module == null) {
return Pair.empty();
}
K2JSModuleComponent jsModuleComponent = K2JSModuleComponent.getInstance(module);
String pathToJavaScriptLibrary = jsModuleComponent.getPathToJavaScriptLibrary();
String basePath = ModuleRootManager.getInstance(module).getContentRoots()[0].getPath();
return Pair.create(basePath + pathToJavaScriptLibrary, jsModuleComponent.getEcmaVersion().toString());
}
@Nullable
public static VirtualFile findIndicationFileInContentRoots(@NotNull Project project) {
VirtualFile[] roots = ProjectRootManager.getInstance(project).getContentRoots();
for (VirtualFile root : roots) {
for (VirtualFile child : root.getChildren()) {
if (child.getName().equals(INDICATION_FILE_NAME)) {
return child;
}
private static Module getJSModule(@NotNull Project project) {
Module[] modules = ModuleManager.getInstance(project).getModules();
for (Module module : modules) {
if (isJsModule(module)) {
return module;
}
}
return null;
}
//TODO: refactor
@NotNull
public static Pair<String, String> getLibLocationAndTargetForProject(@NotNull Project project) {
VirtualFile indicationFile = findIndicationFileInContentRoots(project);
Logger logger = Logger.getInstance(JsModuleDetector.class);
if (indicationFile == null) {
logger.error("Indication file not found for project " + project.getName());
return Pair.empty();
}
try {
InputStream stream = indicationFile.getInputStream();
String text = FileUtil.loadTextAndClose(stream);
if (text.isEmpty()) {
logger.error("Indication file is corrupted for project " + project.getName());
return Pair.empty();
}
String[] lines = text.split("\n");
if (lines.length == 0) {
logger.error("Indication file " + indicationFile.getPath() + "is empty");
return Pair.empty();
}
String pathToLibFile = lines[0];
String version = lines.length >= 2 ? lines[1] : null;
String pathToIndicationFileLocation = indicationFile.getParent().getPath();
return new Pair<String, String>(pathToIndicationFileLocation + "/" + pathToLibFile, version);
}
catch (IOException e) {
logger.error("Could not open file " + indicationFile.getPath());
return Pair.empty();
}
}
}
@@ -0,0 +1,127 @@
/*
* Copyright 2010-2012 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 org.jetbrains.jet.plugin.project;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleComponent;
import com.intellij.openapi.roots.impl.storage.ClasspathStorage;
import com.intellij.util.xmlb.XmlSerializerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.k2js.config.EcmaVersion;
/**
* @author Pavel Talanov
*/
@State(
name = "K2JSModule",
storages = @Storage(
id = ClasspathStorage.DEFAULT_STORAGE,
file = "$MODULE_FILE$"
)
)
public final class K2JSModuleComponent implements ModuleComponent, PersistentStateComponent<K2JSModuleComponent> {
@NotNull
public static K2JSModuleComponent getInstance(@NotNull Module module) {
return module.getComponent(K2JSModuleComponent.class);
}
private boolean isJavaScriptModule;
@Nullable
private String pathToJavaScriptLibrary;
@NotNull
private EcmaVersion ecmaVersion;
@NotNull
public EcmaVersion getEcmaVersion() {
return ecmaVersion;
}
public K2JSModuleComponent() {
this.isJavaScriptModule = false;
this.pathToJavaScriptLibrary = null;
this.ecmaVersion = EcmaVersion.defaultVersion();
}
public void setEcmaVersion(@NotNull EcmaVersion ecmaVersion) {
this.ecmaVersion = ecmaVersion;
}
public boolean isJavaScriptModule() {
return isJavaScriptModule;
}
public void setJavaScriptModule(boolean javaScriptModule) {
isJavaScriptModule = javaScriptModule;
}
@Nullable
public String getPathToJavaScriptLibrary() {
return pathToJavaScriptLibrary;
}
public void setPathToJavaScriptLibrary(@Nullable String pathToJavaScriptLibrary) {
this.pathToJavaScriptLibrary = pathToJavaScriptLibrary;
}
@Override
public void projectOpened() {
//do nothing
}
@Override
public void projectClosed() {
//do nothing
}
@Override
public void moduleAdded() {
//do nothing
}
@Override
public void initComponent() {
//do nothing
}
@Override
public void disposeComponent() {
//do nothing
}
@NotNull
@Override
public String getComponentName() {
return "Kotlin to JavaScript module configuration";
}
@Override
public K2JSModuleComponent getState() {
return this;
}
@Override
public void loadState(K2JSModuleComponent state) {
XmlSerializerUtil.copyBean(state, this);
}
}
@@ -56,7 +56,7 @@ import javax.swing.*;
import java.io.File;
import java.io.IOException;
import static org.jetbrains.jet.plugin.project.JsModuleDetector.isJsProject;
import static org.jetbrains.jet.plugin.project.JsModuleDetector.isJsModule;
public class ConfigureKotlinLibraryNotificationProvider implements EditorNotifications.Provider<EditorNotificationPanel> {
private static final Key<EditorNotificationPanel> KEY = Key.create("configure.kotlin.library");
@@ -86,7 +86,7 @@ public class ConfigureKotlinLibraryNotificationProvider implements EditorNotific
if (isMavenModule(module)) return null;
if (isJsProject(myProject)) return null;
if (isJsModule(module)) return null;
GlobalSearchScope scope = module.getModuleWithDependenciesAndLibrariesScope(false);
if (JavaPsiFacade.getInstance(myProject).findClass("jet.JetObject", scope) == null) {
@@ -178,7 +178,7 @@ public class ConfigureKotlinLibraryNotificationProvider implements EditorNotific
}
private void setUpJSModule(@NotNull Module module) {
JsModuleSetUp.doSetUpModule(module.getProject(), new Runnable() {
JsModuleSetUp.doSetUpModule(module, new Runnable() {
@Override
public void run() {
updateNotifications();
@@ -20,14 +20,11 @@ import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.plugin.k2jsrun.K2JSRunnerUtils;
import org.jetbrains.jet.plugin.project.JsModuleDetector;
import org.jetbrains.jet.plugin.project.K2JSModuleComponent;
import org.jetbrains.jet.utils.PathUtil;
import java.io.File;
@@ -45,13 +42,13 @@ public final class JsModuleSetUp {
private JsModuleSetUp() {
}
public static void doSetUpModule(@Nullable Project project, @NotNull Runnable continuation) {
if (project == null) {
notifyFailure("Internal error: Project not found.");
public static void doSetUpModule(@Nullable Module module, @NotNull Runnable continuation) {
if (module == null) {
notifyFailure("Internal error: Module not found.");
return;
}
File rootDir = getRootDir(project);
File rootDir = getRootDir(module);
if (!rootDir.isDirectory()) {
notifyFailure("Internal error: Broken content root.");
return;
@@ -59,19 +56,11 @@ public final class JsModuleSetUp {
if (!copyJsLibFiles(rootDir)) return;
File file = new File(rootDir, JsModuleDetector.INDICATION_FILE_NAME);
if (file.exists()) {
notifyInfo("File " + file.getName() + " already exists.");
// If the notification in the editor did not disappear due to
// slow file system events, this will remove the notification
// when the user clicks for the second time
refreshRootDir(project, continuation);
return;
}
K2JSModuleComponent jsModuleComponent = K2JSModuleComponent.getInstance(module);
jsModuleComponent.setJavaScriptModule(true);
jsModuleComponent.setPathToJavaScriptLibrary("/lib/" + PathUtil.JS_LIB_JAR_NAME);
createIndicationFile(file);
refreshRootDir(project, continuation);
refreshRootDir(module, continuation);
}
private static boolean copyJsLibFiles(@NotNull File rootDir) {
@@ -85,19 +74,10 @@ public final class JsModuleSetUp {
return doCopyJsLibFiles(Arrays.asList(jsLibJarPath, jsLibJsPath), rootDir);
}
private static void refreshRootDir(@NotNull Project project, @NotNull Runnable continuation) {
private static void refreshRootDir(@NotNull Module project, @NotNull Runnable continuation) {
getContentRoot(project).refresh(true, true, continuation);
}
private static void createIndicationFile(@NotNull File file) {
try {
FileUtil.writeToFile(file, "lib/" + PathUtil.JS_LIB_JAR_NAME);
}
catch (IOException e) {
notifyFailure("Failed to write file " + file.getName());
}
}
private static boolean doCopyJsLibFiles(@NotNull List<File> files, @NotNull File rootDir) {
try {
File lib = new File(rootDir, "lib");
@@ -113,14 +93,13 @@ public final class JsModuleSetUp {
}
@NotNull
private static File getRootDir(@NotNull Project project) {
VirtualFile contentRoot = getContentRoot(project);
private static File getRootDir(@NotNull Module module) {
VirtualFile contentRoot = getContentRoot(module);
return new File(contentRoot.getPath());
}
@NotNull
private static VirtualFile getContentRoot(@NotNull Project project) {
Module module = K2JSRunnerUtils.getJsModule(project);
private static VirtualFile getContentRoot(@NotNull Module module) {
return ModuleRootManager.getInstance(module).getContentRoots()[0];
}
@@ -129,10 +108,4 @@ public final class JsModuleSetUp {
message,
NotificationType.ERROR));
}
public static void notifyInfo(@NotNull String message) {
Notifications.Bus.notify(new Notification("Set Up Kotlin to JavaScript Module", "Information",
message,
NotificationType.INFORMATION));
}
}
@@ -59,7 +59,7 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im
return null;
}
if (JsModuleDetector.isJsProject(module.getProject())) {
if (JsModuleDetector.isJsModule(module)) {
return null;
}