From 4f89d8be3ed21ec6d9a1a2b392eb4d09deb94751 Mon Sep 17 00:00:00 2001 From: pTalanov Date: Mon, 4 Jun 2012 21:11:39 +0400 Subject: [PATCH] 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 --- idea/src/META-INF/plugin.xml | 6 + .../jet/plugin/compiler/JetCompiler.java | 5 +- .../jet/plugin/compiler/K2JSCompiler.java | 16 +-- .../jet/plugin/k2jsrun/K2JSRunnerUtils.java | 1 + .../libraries/JetSourceNavigationHelper.java | 2 +- .../project/AnalyzerFacadeProvider.java | 43 +++++- .../jet/plugin/project/JsModuleDetector.java | 74 +++------- .../plugin/project/K2JSModuleComponent.java | 127 ++++++++++++++++++ ...gureKotlinLibraryNotificationProvider.java | 6 +- .../jet/plugin/quickfix/JsModuleSetUp.java | 53 ++------ .../run/JetRunConfigurationProducer.java | 2 +- 11 files changed, 222 insertions(+), 113 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/project/K2JSModuleComponent.java diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 00df0658049..a7049fcc191 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -29,6 +29,12 @@ + + + org.jetbrains.jet.plugin.project.K2JSModuleComponent + + + diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java index c66cdc96710..0b6e3213ad5 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java @@ -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; diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/K2JSCompiler.java b/idea/src/org/jetbrains/jet/plugin/compiler/K2JSCompiler.java index dc8589e46fe..20b7f6831f6 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/K2JSCompiler.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/K2JSCompiler.java @@ -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 args) { - Pair data = JsModuleDetector.getLibLocationAndTargetForProject(project); - if (data.first != null) { + Pair 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); } } diff --git a/idea/src/org/jetbrains/jet/plugin/k2jsrun/K2JSRunnerUtils.java b/idea/src/org/jetbrains/jet/plugin/k2jsrun/K2JSRunnerUtils.java index b0b73a5dfdc..65ff421aa7b 100644 --- a/idea/src/org/jetbrains/jet/plugin/k2jsrun/K2JSRunnerUtils.java +++ b/idea/src/org/jetbrains/jet/plugin/k2jsrun/K2JSRunnerUtils.java @@ -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."); diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/JetSourceNavigationHelper.java b/idea/src/org/jetbrains/jet/plugin/libraries/JetSourceNavigationHelper.java index 5173e6d91c7..f89015e9dd7 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/JetSourceNavigationHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/libraries/JetSourceNavigationHelper.java @@ -71,7 +71,7 @@ public class JetSourceNavigationHelper { } final Project project = declaration.getProject(); final List libraryFiles = findAllSourceFilesWhichContainIdentifier(declaration); - BindingContext bindingContext = AnalyzerFacadeProvider.getAnalyzerFacadeForProject(project).analyzeFiles( + BindingContext bindingContext = AnalyzerFacadeProvider.getAnalyzerFacadeForProject().analyzeFiles( project, libraryFiles, Collections.emptyList(), diff --git a/idea/src/org/jetbrains/jet/plugin/project/AnalyzerFacadeProvider.java b/idea/src/org/jetbrains/jet/plugin/project/AnalyzerFacadeProvider.java index 84ec04b4ce5..4d75740f9a2 100644 --- a/idea/src/org/jetbrains/jet/plugin/project/AnalyzerFacadeProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/project/AnalyzerFacadeProvider.java @@ -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; + } } diff --git a/idea/src/org/jetbrains/jet/plugin/project/JsModuleDetector.java b/idea/src/org/jetbrains/jet/plugin/project/JsModuleDetector.java index dbf3e862692..7cf1ce91429 100644 --- a/idea/src/org/jetbrains/jet/plugin/project/JsModuleDetector.java +++ b/idea/src/org/jetbrains/jet/plugin/project/JsModuleDetector.java @@ -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 *

* 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 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 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(pathToIndicationFileLocation + "/" + pathToLibFile, version); - } - catch (IOException e) { - logger.error("Could not open file " + indicationFile.getPath()); - return Pair.empty(); - } - } } diff --git a/idea/src/org/jetbrains/jet/plugin/project/K2JSModuleComponent.java b/idea/src/org/jetbrains/jet/plugin/project/K2JSModuleComponent.java new file mode 100644 index 00000000000..1ef482548c6 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/project/K2JSModuleComponent.java @@ -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 { + + @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); + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ConfigureKotlinLibraryNotificationProvider.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ConfigureKotlinLibraryNotificationProvider.java index 0b873b1259c..25a5b52de47 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ConfigureKotlinLibraryNotificationProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ConfigureKotlinLibraryNotificationProvider.java @@ -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 { private static final Key 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(); diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/JsModuleSetUp.java b/idea/src/org/jetbrains/jet/plugin/quickfix/JsModuleSetUp.java index b2bc6a2b8fb..388c6dd3ab1 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/JsModuleSetUp.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/JsModuleSetUp.java @@ -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 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)); - } } diff --git a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java index b6c72cbb6e3..f237d4942f5 100644 --- a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java +++ b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java @@ -59,7 +59,7 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im return null; } - if (JsModuleDetector.isJsProject(module.getProject())) { + if (JsModuleDetector.isJsModule(module)) { return null; }