mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-10-01 17:03:12 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -28,11 +28,8 @@ import org.jdom.Element;
|
||||
* @author <a href="mailto:aefimov.box@gmail.com">Alexey Efimov</a>
|
||||
*/
|
||||
@State(
|
||||
name = "Images.OptionsManager",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages = {
|
||||
@Storage(file = StoragePathMacros.APP_CONFIG + "/images.support.xml")
|
||||
}
|
||||
name = "Images.OptionsManager",
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/images.support.xml", roamingType = RoamingType.DISABLED)}
|
||||
)
|
||||
final class OptionsManagerImpl extends OptionsManager implements PersistentStateComponent<Element> {
|
||||
private final OptionsImpl options = new OptionsImpl();
|
||||
|
||||
@@ -73,7 +73,10 @@ import com.intellij.openapi.vfs.newvfs.BulkFileListener;
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.FileNameCache;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import com.intellij.util.concurrency.SequentialTaskExecutor;
|
||||
import com.intellij.util.containers.IntArrayList;
|
||||
@@ -897,9 +900,6 @@ public class BuildManager implements ApplicationComponent{
|
||||
if (!Registry.is("compiler.process.use.memory.temp.cache")) {
|
||||
cmdLine.addParameter("-D"+ GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION + "=false");
|
||||
}
|
||||
if (Registry.is("compiler.process.use.external.javac")) {
|
||||
cmdLine.addParameter("-D"+ GlobalOptions.USE_EXTERNAL_JAVAC_OPTION);
|
||||
}
|
||||
|
||||
// javac's VM should use the same default locale that IDEA uses in order for javac to print messages in 'correct' language
|
||||
if (mySystemCharset != null) {
|
||||
@@ -941,7 +941,6 @@ public class BuildManager implements ApplicationComponent{
|
||||
cmdLine.addParameter(launcherClass.getName());
|
||||
|
||||
final List<String> cp = ClasspathBootstrap.getBuildProcessApplicationClasspath(true);
|
||||
cp.add(getJpsPluginSystemClassesPath());
|
||||
cp.addAll(myClasspathManager.getBuildProcessPluginsClasspath(project));
|
||||
if (isProfilingMode) {
|
||||
cp.add(new File(workDirectory, "yjp-controller-api-redist.jar").getPath());
|
||||
@@ -967,17 +966,6 @@ public class BuildManager implements ApplicationComponent{
|
||||
};
|
||||
}
|
||||
|
||||
private static String getJpsPluginSystemClassesPath() {
|
||||
File classesRoot = new File(PathUtil.getJarPathForClass(BuildManager.class));
|
||||
if (classesRoot.isDirectory()) {
|
||||
//running from sources: load classes from .../out/production/jps-plugin-system
|
||||
return new File(classesRoot.getParentFile(), "jps-plugin-system").getAbsolutePath();
|
||||
}
|
||||
else {
|
||||
return new File(classesRoot.getParentFile(), "rt/jps-plugin-system.jar").getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
public File getBuildSystemDirectory() {
|
||||
return new File(mySystemDirectory, SYSTEM_ROOT);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.intellij.xdebugger.XDebugProcess;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.impl.frame.XDebugView;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -159,8 +160,11 @@ public abstract class DebuggerAction extends AnAction {
|
||||
});
|
||||
}
|
||||
|
||||
public static void refreshViews(XValueNodeImpl node) {
|
||||
final XDebugSession session = XDebugView.getSession(node.getTree());
|
||||
public static void refreshViews(@NotNull XValueNodeImpl node) {
|
||||
refreshViews(XDebugView.getSession(node.getTree()));
|
||||
}
|
||||
|
||||
public static void refreshViews(@Nullable XDebugSession session) {
|
||||
if (session != null) {
|
||||
XDebugProcess process = session.getDebugProcess();
|
||||
if (process instanceof JavaDebugProcess) {
|
||||
|
||||
+3
-1
@@ -50,6 +50,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.intellij.openapi.actionSystem.PlatformDataKeys.CONTEXT_COMPONENT;
|
||||
|
||||
/*
|
||||
* Class SetValueAction
|
||||
* @author Jeka
|
||||
@@ -72,7 +74,7 @@ public class JavaMarkObjectActionHandler extends MarkObjectActionHandler {
|
||||
final DebuggerTree tree = node.getTree();
|
||||
tree.saveState(node);
|
||||
|
||||
final Component parent = event.getInputEvent().getComponent();
|
||||
final Component parent = event.getData(CONTEXT_COMPONENT);
|
||||
final ValueDescriptorImpl valueDescriptor = ((ValueDescriptorImpl)descriptor);
|
||||
final DebuggerContextImpl debuggerContext = tree.getDebuggerContext();
|
||||
final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.debugger.engine;
|
||||
|
||||
import com.intellij.Patches;
|
||||
import com.intellij.debugger.*;
|
||||
import com.intellij.debugger.actions.DebuggerAction;
|
||||
import com.intellij.debugger.actions.DebuggerActions;
|
||||
import com.intellij.debugger.apiAdapters.ConnectionServiceWrapper;
|
||||
import com.intellij.debugger.engine.evaluation.*;
|
||||
@@ -170,10 +171,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
|
||||
final DebuggerSession session = mySession;
|
||||
if (session != null && session.isAttached()) {
|
||||
session.refresh(true);
|
||||
XDebugSession xDebugSession = mySession.getXDebugSession();
|
||||
if (xDebugSession != null) {
|
||||
xDebugSession.rebuildViews();
|
||||
}
|
||||
DebuggerAction.refreshViews(mySession.getXDebugSession());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -429,6 +429,7 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
|
||||
public String getEvaluationExpression() {
|
||||
if (evaluationExpression == null) {
|
||||
// TODO: change API to allow to calculate it asynchronously
|
||||
if (myEvaluationContext.getSuspendContext().isResumed()) return null;
|
||||
DebugProcessImpl debugProcess = myEvaluationContext.getDebugProcess();
|
||||
debugProcess.getManagerThread().invokeAndWait(new DebuggerCommandImpl() {
|
||||
@Override
|
||||
|
||||
@@ -100,10 +100,12 @@ public class JavaValueModifier extends XValueModifier {
|
||||
@Override
|
||||
public void setValue(@NotNull String expression, @NotNull XModificationCallback callback) {
|
||||
final NodeDescriptorImpl descriptor = myJavaValue.getDescriptor();
|
||||
if (!(descriptor instanceof ValueDescriptorImpl)) {
|
||||
if(!((ValueDescriptorImpl)descriptor).canSetValue()) {
|
||||
return;
|
||||
}
|
||||
if(!((ValueDescriptorImpl)descriptor).canSetValue()) {
|
||||
|
||||
if (myJavaValue.getEvaluationContext().getSuspendContext().isResumed()) {
|
||||
callback.errorOccurred(DebuggerBundle.message("error.context.has.changed"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@State(
|
||||
name = "RecentProjectsManager",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages = {
|
||||
@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml"),
|
||||
@Storage(file = StoragePathMacros.APP_CONFIG + "/recentProjects.xml")
|
||||
@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", roamingType = RoamingType.DISABLED),
|
||||
@Storage(file = StoragePathMacros.APP_CONFIG + "/recentProjects.xml", roamingType = RoamingType.DISABLED)
|
||||
},
|
||||
storageChooser = LastStorageChooserForWrite.class
|
||||
)
|
||||
|
||||
+6
-7
@@ -22,17 +22,16 @@ package com.intellij.openapi.projectRoots.impl;
|
||||
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.projectRoots.*;
|
||||
import com.intellij.openapi.projectRoots.JavaSdk;
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.projectRoots.SdkTypeId;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import org.jdom.Element;
|
||||
|
||||
@State(
|
||||
name="ProjectJdkTable",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages= {
|
||||
@Storage(
|
||||
file = StoragePathMacros.APP_CONFIG + "/jdk.table.xml"
|
||||
)}
|
||||
name = "ProjectJdkTable",
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/jdk.table.xml", roamingType = RoamingType.DISABLED)}
|
||||
)
|
||||
public class JavaAwareProjectJdkTableImpl extends ProjectJdkTableImpl {
|
||||
public static JavaAwareProjectJdkTableImpl getInstanceEx() {
|
||||
|
||||
@@ -638,7 +638,7 @@ public class JavaDocInfoGenerator {
|
||||
String text = o.toString();
|
||||
PsiType type = variable.getType();
|
||||
if (type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) {
|
||||
text = "\"" + StringUtil.shortenPathWithEllipsis(text, 120) + "\"";
|
||||
text = "\"" + StringUtil.escapeLineBreak(StringUtil.shortenPathWithEllipsis(text, 120)) + "\"";
|
||||
}
|
||||
else if (type.equalsToText("char")) text = "'" + text + "'";
|
||||
try {
|
||||
|
||||
-2
@@ -30,12 +30,10 @@ import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.containers.IntArrayList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.List;
|
||||
|
||||
public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements PsiLambdaExpression {
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ package org.jetbrains.jps.api;
|
||||
*/
|
||||
public interface GlobalOptions {
|
||||
String USE_MEMORY_TEMP_CACHE_OPTION = "use.memory.temp.cache";
|
||||
String USE_EXTERNAL_JAVAC_OPTION = "use.external.javac.process";
|
||||
String GENERATE_CLASSPATH_INDEX_OPTION = "generate.classpath.index";
|
||||
String COMPILE_PARALLEL_OPTION = "compile.parallel";
|
||||
String COMPILE_PARALLEL_MAX_THREADS_OPTION = "compile.parallel.max.threads";
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.jetbrains.jps.service.SharedThreadPool;
|
||||
import java.io.*;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
@@ -214,7 +215,7 @@ public class BuildMain {
|
||||
public void run() {
|
||||
//noinspection finally
|
||||
try {
|
||||
ourEventLoopGroup.shutdownGracefully();
|
||||
ourEventLoopGroup.shutdownGracefully(0, 15, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
System.exit(0);
|
||||
|
||||
@@ -32,7 +32,7 @@ import net.n3.nanoxml.IXMLBuilder;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.builders.java.JavaCompilingTool;
|
||||
import org.jetbrains.jps.builders.java.JavaSourceTransformer;
|
||||
import org.jetbrains.jps.javac.JavacServer;
|
||||
import org.jetbrains.jps.javac.ExternalJavacProcess;
|
||||
import org.jetbrains.jps.model.JpsModel;
|
||||
import org.jetbrains.jps.model.impl.JpsModelImpl;
|
||||
import org.jetbrains.jps.model.serialization.JpsProjectLoader;
|
||||
@@ -145,6 +145,8 @@ public class ClasspathBootstrap {
|
||||
cp.add(getResourcePath(NotNullVerifyingInstrumenter.class)); // not-null
|
||||
cp.add(getResourcePath(IXMLBuilder.class)); // nano-xml
|
||||
cp.add(getResourcePath(SequenceLock.class)); // jsr166
|
||||
cp.add(getJpsPluginSystemClassesPath().getAbsolutePath().replace('\\', '/'));
|
||||
|
||||
//don't forget to update layoutCommunityJps() in layouts.gant accordingly
|
||||
|
||||
if (!isLauncherUsed) {
|
||||
@@ -176,9 +178,9 @@ public class ClasspathBootstrap {
|
||||
}
|
||||
}
|
||||
|
||||
public static List<File> getJavacServerClasspath(String sdkHome, JavaCompilingTool compilingTool) {
|
||||
public static List<File> getExternalJavacProcessClasspath(String sdkHome, JavaCompilingTool compilingTool) {
|
||||
final Set<File> cp = new LinkedHashSet<File>();
|
||||
cp.add(getResourceFile(JavacServer.class)); // self
|
||||
cp.add(getResourceFile(ExternalJavacProcess.class)); // self
|
||||
// util
|
||||
for (String path : PathManager.getUtilClassPath()) {
|
||||
cp.add(new File(path));
|
||||
@@ -187,7 +189,8 @@ public class ClasspathBootstrap {
|
||||
cp.add(getResourceFile(JpsModelImpl.class)); // jps-model-impl
|
||||
cp.add(getResourceFile(Message.class)); // protobuf
|
||||
cp.add(getResourceFile(NetUtil.class)); // netty
|
||||
|
||||
cp.add(getJpsPluginSystemClassesPath());
|
||||
|
||||
final Class<StandardJavaFileManager> optimizedFileManagerClass = getOptimizedFileManagerClass();
|
||||
if (optimizedFileManagerClass != null) {
|
||||
cp.add(getResourceFile(optimizedFileManagerClass)); // optimizedFileManager, if applicable
|
||||
@@ -201,38 +204,33 @@ public class ClasspathBootstrap {
|
||||
LOG.info(th);
|
||||
}
|
||||
|
||||
final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler();
|
||||
if (systemCompiler != null) {
|
||||
try {
|
||||
final String localJarPath = FileUtil.toSystemIndependentName(getResourceFile(systemCompiler.getClass()).getPath());
|
||||
final String localJavaHome = FileUtil.toSystemIndependentName(SystemProperties.getJavaHome());
|
||||
if (FileUtil.pathsEqual(localJavaHome, FileUtil.toSystemIndependentName(sdkHome))) {
|
||||
cp.add(new File(localJarPath));
|
||||
}
|
||||
else {
|
||||
// sdkHome is not the same as the sdk used to run this process
|
||||
final File candidate = new File(sdkHome, "lib/tools.jar");
|
||||
if (candidate.exists()) {
|
||||
cp.add(candidate);
|
||||
}
|
||||
else {
|
||||
// last resort
|
||||
String relPath = FileUtil.getRelativePath(localJavaHome, localJarPath, '/');
|
||||
try {
|
||||
final String localJavaHome = FileUtil.toSystemIndependentName(SystemProperties.getJavaHome());
|
||||
// sdkHome is not the same as the sdk used to run this process
|
||||
final File candidate = new File(sdkHome, "lib/tools.jar");
|
||||
if (candidate.exists()) {
|
||||
cp.add(candidate);
|
||||
}
|
||||
else {
|
||||
// last resort
|
||||
final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler();
|
||||
if (systemCompiler != null) {
|
||||
final String localJarPath = FileUtil.toSystemIndependentName(getResourceFile(systemCompiler.getClass()).getPath());
|
||||
String relPath = FileUtil.getRelativePath(localJavaHome, localJarPath, '/');
|
||||
if (relPath != null) {
|
||||
if (relPath.contains("..")) {
|
||||
relPath = FileUtil.getRelativePath(FileUtil.toSystemIndependentName(new File(localJavaHome).getParent()), localJarPath, '/');
|
||||
}
|
||||
if (relPath != null) {
|
||||
if (relPath.contains("..")) {
|
||||
relPath = FileUtil.getRelativePath(FileUtil.toSystemIndependentName(new File(localJavaHome).getParent()), localJarPath, '/');
|
||||
}
|
||||
if (relPath != null) {
|
||||
final File targetFile = new File(sdkHome, relPath);
|
||||
cp.add(targetFile); // tools.jar
|
||||
}
|
||||
final File targetFile = new File(sdkHome, relPath);
|
||||
cp.add(targetFile); // tools.jar
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable th) {
|
||||
LOG.info(th);
|
||||
}
|
||||
}
|
||||
catch (Throwable th) {
|
||||
LOG.info(th);
|
||||
}
|
||||
|
||||
cp.addAll(compilingTool.getAdditionalClasspath());
|
||||
@@ -286,4 +284,16 @@ public class ClasspathBootstrap {
|
||||
public static File getResourceFile(Class aClass) {
|
||||
return new File(getResourcePath(aClass));
|
||||
}
|
||||
|
||||
private static File getJpsPluginSystemClassesPath() {
|
||||
File classesRoot = new File(getResourcePath(ClasspathBootstrap.class));
|
||||
if (classesRoot.isDirectory()) {
|
||||
//running from sources: load classes from .../out/production/jps-plugin-system
|
||||
return new File(classesRoot.getParentFile(), "jps-plugin-system");
|
||||
}
|
||||
else {
|
||||
return new File(classesRoot.getParentFile(), "rt/jps-plugin-system.jar");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import org.jetbrains.jps.ModuleChunk;
|
||||
import org.jetbrains.jps.TimingLog;
|
||||
import org.jetbrains.jps.api.CanceledStatus;
|
||||
import org.jetbrains.jps.api.GlobalOptions;
|
||||
import org.jetbrains.jps.api.RequestFuture;
|
||||
import org.jetbrains.jps.builders.*;
|
||||
import org.jetbrains.jps.builders.impl.BuildOutputConsumerImpl;
|
||||
import org.jetbrains.jps.builders.impl.BuildTargetChunk;
|
||||
@@ -50,12 +49,12 @@ import org.jetbrains.jps.builders.storage.SourceToOutputMapping;
|
||||
import org.jetbrains.jps.cmdline.BuildRunner;
|
||||
import org.jetbrains.jps.cmdline.ProjectDescriptor;
|
||||
import org.jetbrains.jps.incremental.fs.BuildFSState;
|
||||
import org.jetbrains.jps.incremental.java.ExternalJavacDescriptor;
|
||||
import org.jetbrains.jps.incremental.messages.*;
|
||||
import org.jetbrains.jps.incremental.storage.BuildTargetConfiguration;
|
||||
import org.jetbrains.jps.incremental.storage.OneToManyPathsMapping;
|
||||
import org.jetbrains.jps.incremental.storage.OutputToTargetRegistry;
|
||||
import org.jetbrains.jps.indices.ModuleExcludeIndex;
|
||||
import org.jetbrains.jps.javac.ExternalJavacServer;
|
||||
import org.jetbrains.jps.javac.JavacMain;
|
||||
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
|
||||
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration;
|
||||
@@ -313,17 +312,10 @@ public class IncProjectBuilder {
|
||||
pd.timestamps.getStorage().force();
|
||||
pd.dataManager.flush(false);
|
||||
}
|
||||
final ExternalJavacDescriptor descriptor = ExternalJavacDescriptor.KEY.get(context);
|
||||
if (descriptor != null) {
|
||||
try {
|
||||
final RequestFuture future = descriptor.client.sendShutdownRequest();
|
||||
future.waitFor(500L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
finally {
|
||||
// ensure process is not running
|
||||
descriptor.process.destroyProcess();
|
||||
}
|
||||
ExternalJavacDescriptor.KEY.set(context, null);
|
||||
final ExternalJavacServer server = ExternalJavacServer.KEY.get(context);
|
||||
if (server != null) {
|
||||
server.stop();
|
||||
ExternalJavacServer.KEY.set(context, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-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.jps.incremental.java;
|
||||
|
||||
import com.intellij.execution.process.BaseOSProcessHandler;
|
||||
import org.jetbrains.jps.incremental.GlobalContextKey;
|
||||
import org.jetbrains.jps.javac.JavacServerClient;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/24/12
|
||||
*/
|
||||
public class ExternalJavacDescriptor {
|
||||
public static final GlobalContextKey<ExternalJavacDescriptor> KEY = GlobalContextKey.create("_external_javac_descriptor_");
|
||||
|
||||
public final BaseOSProcessHandler process;
|
||||
public final JavacServerClient client;
|
||||
|
||||
public ExternalJavacDescriptor(BaseOSProcessHandler process, JavacServerClient client) {
|
||||
this.process = process;
|
||||
this.client = client;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.jetbrains.jps.incremental.java;
|
||||
|
||||
import com.intellij.execution.process.BaseOSProcessHandler;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Key;
|
||||
@@ -32,8 +31,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.ModuleChunk;
|
||||
import org.jetbrains.jps.ProjectPaths;
|
||||
import org.jetbrains.jps.api.GlobalOptions;
|
||||
import org.jetbrains.jps.api.RequestFuture;
|
||||
import org.jetbrains.jps.builders.BuildRootIndex;
|
||||
import org.jetbrains.jps.builders.DirtyFilesHolder;
|
||||
import org.jetbrains.jps.builders.FileProcessor;
|
||||
@@ -63,13 +60,11 @@ import org.jetbrains.jps.model.module.JpsModule;
|
||||
import org.jetbrains.jps.model.module.JpsModuleType;
|
||||
import org.jetbrains.jps.service.JpsServiceManager;
|
||||
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.*;
|
||||
import java.io.*;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
@@ -81,7 +76,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
public static final String BUILDER_NAME = "java";
|
||||
private static final String JAVA_EXTENSION = "java";
|
||||
private static final String DOT_JAVA_EXTENSION = "." + JAVA_EXTENSION;
|
||||
public static final boolean USE_EMBEDDED_JAVAC = System.getProperty(GlobalOptions.USE_EXTERNAL_JAVAC_OPTION) == null;
|
||||
private static final Key<Integer> JAVA_COMPILER_VERSION_KEY = Key.create("_java_compiler_version_");
|
||||
public static final Key<Boolean> IS_ENABLED = Key.create("_java_compiler_enabled_");
|
||||
private static final Key<JavaCompilingTool> COMPILING_TOOL = Key.create("_java_compiling_tool_");
|
||||
@@ -396,7 +390,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
try {
|
||||
final boolean rc;
|
||||
if (USE_EMBEDDED_JAVAC) {
|
||||
if (!shouldForkCompilerProcess(context, chunk, compilingTool)) {
|
||||
final Collection<File> _platformCp = calcEffectivePlatformCp(platformCp, options, compilingTool);
|
||||
if (_platformCp == null) {
|
||||
diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR,
|
||||
@@ -409,16 +403,18 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
);
|
||||
}
|
||||
else {
|
||||
final JavacServerClient client = ensureJavacServerLaunched(context, compilingTool);
|
||||
final RequestFuture<JavacServerResponseHandler> future = client.sendCompileRequest(
|
||||
options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer
|
||||
);
|
||||
while (!future.waitFor(100L, TimeUnit.MILLISECONDS)) {
|
||||
if (context.getCancelStatus().isCanceled()) {
|
||||
future.cancel(false);
|
||||
}
|
||||
// fork external javac
|
||||
final String sdkHome = getChunkSdkHome(chunk);
|
||||
if (sdkHome == null) {
|
||||
diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "Cannot start javac process for " + chunk.getName() + ": unknown JDK home path.\nPlease check project configuration."));
|
||||
return true;
|
||||
}
|
||||
rc = future.getMessageHandler().isTerminatedSuccessfully();
|
||||
|
||||
final List<String> vmOptions = getCompilationVMOptions(context, compilingTool);
|
||||
final ExternalJavacServer server = ensureJavacServerStarted(context);
|
||||
rc = server.forkJavac(
|
||||
context, options, vmOptions, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer, sdkHome, compilingTool
|
||||
);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -426,6 +422,20 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
counter.await();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldForkCompilerProcess(CompileContext context, ModuleChunk chunk, JavaCompilingTool tool) {
|
||||
final int compilerSdkVersion = getCompilerSdkVersion(context);
|
||||
if (compilerSdkVersion < 9) {
|
||||
// javac up to version 9 supports all previous releases
|
||||
return false;
|
||||
}
|
||||
final int chunkSdkVersion = getChunkSdkVersion(chunk);
|
||||
if (chunkSdkVersion < 0) {
|
||||
return false; // was not able to determine jdk version, assuming in-process compiler
|
||||
}
|
||||
// according to JEP 182: Retiring javac "one plus three back" policy
|
||||
return Math.abs(compilerSdkVersion - chunkSdkVersion) > 3;
|
||||
}
|
||||
|
||||
// If platformCp of the build process is the same as the target plafform, do not specify platformCp explicitly
|
||||
// this will allow javac to resolve against ct.sym file, which is required for the "compilation profiles" feature
|
||||
@@ -482,31 +492,16 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized JavacServerClient ensureJavacServerLaunched(@NotNull CompileContext context, @NotNull JavaCompilingTool compilingTool) throws Exception {
|
||||
final ExternalJavacDescriptor descriptor = ExternalJavacDescriptor.KEY.get(context);
|
||||
if (descriptor != null) {
|
||||
return descriptor.client;
|
||||
private static synchronized ExternalJavacServer ensureJavacServerStarted(@NotNull CompileContext context) throws Exception {
|
||||
ExternalJavacServer server = ExternalJavacServer.KEY.get(context);
|
||||
if (server != null) {
|
||||
return server;
|
||||
}
|
||||
// start server here
|
||||
final int port = findFreePort();
|
||||
final int heapSize = getJavacServerHeapSize(context);
|
||||
|
||||
// use the same jdk that used to run the build process
|
||||
final String javaHome = SystemProperties.getJavaHome();
|
||||
|
||||
final BaseOSProcessHandler processHandler = JavacServerBootstrap.launchJavacServer(
|
||||
javaHome, heapSize, port, Utils.getSystemRoot(), getCompilationVMOptions(context, compilingTool), compilingTool
|
||||
);
|
||||
final JavacServerClient client = new JavacServerClient();
|
||||
try {
|
||||
client.connect("127.0.0.1", port);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
processHandler.destroyProcess();
|
||||
throw new Exception("Failed to connect to external javac process: ", ex);
|
||||
}
|
||||
ExternalJavacDescriptor.KEY.set(context, new ExternalJavacDescriptor(processHandler, client));
|
||||
return client;
|
||||
final int listenPort = findFreePort();
|
||||
server = new ExternalJavacServer();
|
||||
server.start(listenPort);
|
||||
ExternalJavacServer.KEY.set(context, server);
|
||||
return server;
|
||||
}
|
||||
|
||||
private static int convertToNumber(String ver) {
|
||||
@@ -564,17 +559,10 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
return JavacServer.DEFAULT_SERVER_PORT;
|
||||
return ExternalJavacServer.DEFAULT_SERVER_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getJavacServerHeapSize(CompileContext context) {
|
||||
final JpsProject project = context.getProjectDescriptor().getProject();
|
||||
final JpsJavaCompilerConfiguration config = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project);
|
||||
final JpsJavaCompilerOptions options = config.getCurrentCompilerOptions();
|
||||
return options.MAXIMUM_HEAP_SIZE;
|
||||
}
|
||||
|
||||
private static final Key<List<String>> JAVAC_OPTIONS = Key.create("_javac_options_");
|
||||
private static final Key<List<String>> JAVAC_VM_OPTIONS = Key.create("_javac_vm_options_");
|
||||
private static final Key<String> USER_DEFINED_BYTECODE_TARGET = Key.create("_user_defined_bytecode_target_");
|
||||
@@ -628,19 +616,12 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
options.add(langLevel);
|
||||
}
|
||||
|
||||
JpsJavaCompilerConfiguration compilerConfiguration = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(
|
||||
context.getProjectDescriptor().getProject());
|
||||
String bytecodeTarget = null;
|
||||
int chunkSdkVersion = -1;
|
||||
for (JpsModule module : chunk.getModules()) {
|
||||
final JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE);
|
||||
if (sdk != null) {
|
||||
final int moduleSdkVersion = convertToNumber(sdk.getVersionString());
|
||||
if (moduleSdkVersion != 0 /*could determine the version*/&& (chunkSdkVersion < 0 || chunkSdkVersion > moduleSdkVersion)) {
|
||||
chunkSdkVersion = moduleSdkVersion;
|
||||
}
|
||||
}
|
||||
final JpsJavaCompilerConfiguration compilerConfiguration = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(
|
||||
context.getProjectDescriptor().getProject()
|
||||
);
|
||||
|
||||
String bytecodeTarget = null;
|
||||
for (JpsModule module : chunk.getModules()) {
|
||||
final String moduleTarget = compilerConfiguration.getByteCodeTargetLevel(module.getName());
|
||||
if (moduleTarget == null) {
|
||||
continue;
|
||||
@@ -662,6 +643,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
|
||||
final int compilerSdkVersion = getCompilerSdkVersion(context);
|
||||
final int chunkSdkVersion = getChunkSdkVersion(chunk);
|
||||
|
||||
if (bytecodeTarget != null) {
|
||||
options.add("-target");
|
||||
@@ -721,17 +703,19 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
|
||||
private static String getLanguageLevel(JpsModule module) {
|
||||
LanguageLevel level = JpsJavaExtensionService.getInstance().getLanguageLevel(module);
|
||||
if (level == null) return null;
|
||||
switch (level) {
|
||||
case JDK_1_3: return "1.3";
|
||||
case JDK_1_4: return "1.4";
|
||||
case JDK_1_5: return "1.5";
|
||||
case JDK_1_6: return "1.6";
|
||||
case JDK_1_7: return "1.7";
|
||||
case JDK_1_8: return "8";
|
||||
default: return null;
|
||||
final LanguageLevel level = JpsJavaExtensionService.getInstance().getLanguageLevel(module);
|
||||
if (level != null) {
|
||||
switch (level) {
|
||||
case JDK_1_3: return "1.3";
|
||||
case JDK_1_4: return "1.4";
|
||||
case JDK_1_5: return "1.5";
|
||||
case JDK_1_6: return "1.6";
|
||||
case JDK_1_7: return "1.7";
|
||||
case JDK_1_8: return "8";
|
||||
case JDK_1_9: return "9";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isEncodingSet(List<String> options) {
|
||||
@@ -743,7 +727,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static int getCompilerSdkVersion(CompileContext context) {
|
||||
final Integer cached = JAVA_COMPILER_VERSION_KEY.get(context);
|
||||
if (cached != null) {
|
||||
@@ -754,6 +737,30 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
return javaVersion;
|
||||
}
|
||||
|
||||
private static int getChunkSdkVersion(ModuleChunk chunk) {
|
||||
int chunkSdkVersion = -1;
|
||||
for (JpsModule module : chunk.getModules()) {
|
||||
final JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE);
|
||||
if (sdk != null) {
|
||||
final int moduleSdkVersion = convertToNumber(sdk.getVersionString());
|
||||
if (moduleSdkVersion != 0 /*could determine the version*/&& (chunkSdkVersion < 0 || chunkSdkVersion > moduleSdkVersion)) {
|
||||
chunkSdkVersion = moduleSdkVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunkSdkVersion;
|
||||
}
|
||||
|
||||
private static String getChunkSdkHome(ModuleChunk chunk) {
|
||||
for (JpsModule module : chunk.getModules()) {
|
||||
final JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE);
|
||||
if (sdk != null) {
|
||||
return sdk.getHomePath();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void loadCommonJavacOptions(@NotNull CompileContext context, @NotNull JavaCompilingTool compilingTool) {
|
||||
final List<String> options = new ArrayList<String>();
|
||||
final List<String> vmOptions = new ArrayList<String>();
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.jps.javac;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.MessageLite;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.incremental.BinaryContent;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/22/12
|
||||
*/
|
||||
public class ExternalJavacMessageHandler {
|
||||
private final DiagnosticOutputConsumer myDiagnosticSink;
|
||||
private final OutputFileConsumer myOutputSink;
|
||||
@Nullable
|
||||
private final String myEncodingName;
|
||||
private volatile boolean myTerminatedSuccessfully;
|
||||
|
||||
public ExternalJavacMessageHandler(DiagnosticOutputConsumer diagnosticSink,
|
||||
OutputFileConsumer outputSink,
|
||||
@Nullable final String encodingName) {
|
||||
myDiagnosticSink = diagnosticSink;
|
||||
myOutputSink = outputSink;
|
||||
myEncodingName = encodingName;
|
||||
}
|
||||
|
||||
public boolean handleMessage(MessageLite message) {
|
||||
try {
|
||||
final JavacRemoteProto.Message msg = (JavacRemoteProto.Message)message;
|
||||
final JavacRemoteProto.Message.Type messageType = msg.getMessageType();
|
||||
|
||||
if (messageType == JavacRemoteProto.Message.Type.RESPONSE) {
|
||||
final JavacRemoteProto.Message.Response response = msg.getResponse();
|
||||
final JavacRemoteProto.Message.Response.Type responseType = response.getResponseType();
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.BUILD_MESSAGE) {
|
||||
final JavacRemoteProto.Message.Response.CompileMessage compileMessage = response.getCompileMessage();
|
||||
final JavacRemoteProto.Message.Response.CompileMessage.Kind messageKind = compileMessage.getKind();
|
||||
|
||||
if (messageKind == JavacRemoteProto.Message.Response.CompileMessage.Kind.STD_OUT) {
|
||||
if (compileMessage.hasText()) {
|
||||
myDiagnosticSink.outputLineAvailable(compileMessage.getText());
|
||||
}
|
||||
}
|
||||
else {
|
||||
final String sourceUri = compileMessage.hasSourceUri()? compileMessage.getSourceUri() : null;
|
||||
final JavaFileObject srcFileObject = sourceUri != null? new DummyJavaFileObject(URI.create(sourceUri)) : null;
|
||||
myDiagnosticSink.report(new DummyDiagnostic(convertKind(messageKind), srcFileObject, compileMessage));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.OUTPUT_OBJECT) {
|
||||
final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject();
|
||||
final JavacRemoteProto.Message.Response.OutputObject.Kind kind = outputObject.getKind();
|
||||
|
||||
final String outputRoot = outputObject.hasOutputRoot()? outputObject.getOutputRoot() : null;
|
||||
final File outputRootFile = outputRoot != null? new File(outputRoot) : null;
|
||||
|
||||
final BinaryContent fileObjectContent;
|
||||
final ByteString content = outputObject.hasContent()? outputObject.getContent() : null;
|
||||
if (content != null) {
|
||||
final byte[] bytes = content.toByteArray();
|
||||
fileObjectContent = new BinaryContent(bytes, 0, bytes.length);
|
||||
}
|
||||
else {
|
||||
fileObjectContent = null;
|
||||
}
|
||||
|
||||
final String sourceUri = outputObject.hasSourceUri()? outputObject.getSourceUri() : null;
|
||||
final URI srcUri = sourceUri != null? URI.create(sourceUri) : null;
|
||||
final OutputFileObject fileObject = new OutputFileObject(
|
||||
null,
|
||||
outputRootFile,
|
||||
outputObject.hasRelativePath()? outputObject.getRelativePath() : null,
|
||||
new File(outputObject.getFilePath()),
|
||||
convertKind(kind),
|
||||
outputObject.hasClassName()? outputObject.getClassName() : null,
|
||||
srcUri,
|
||||
myEncodingName, fileObjectContent
|
||||
);
|
||||
|
||||
myOutputSink.save(fileObject);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.SRC_FILE_LOADED) {
|
||||
final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject();
|
||||
final File file = new File(outputObject.getFilePath());
|
||||
myDiagnosticSink.javaFileLoaded(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.CLASS_DATA) {
|
||||
final JavacRemoteProto.Message.Response.ClassData data = response.getClassData();
|
||||
final String className = data.getClassName();
|
||||
final Collection<String> imports = data.getImportStatementList();
|
||||
final Collection<String> staticImports = data.getStaticImportList();
|
||||
myDiagnosticSink.registerImports(className, imports, staticImports);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.BUILD_COMPLETED) {
|
||||
if (response.hasCompletionStatus()) {
|
||||
myTerminatedSuccessfully = response.getCompletionStatus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Exception("Unsupported response type: " + responseType.name());
|
||||
}
|
||||
|
||||
if (messageType == JavacRemoteProto.Message.Type.FAILURE) {
|
||||
final JavacRemoteProto.Message.Failure failure = msg.getFailure();
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
if (failure.hasDescription()) {
|
||||
buf.append(failure.getDescription());
|
||||
}
|
||||
if (failure.hasStacktrace()) {
|
||||
if (buf.length() > 0) {
|
||||
buf.append("\n");
|
||||
}
|
||||
buf.append(failure.getStacktrace());
|
||||
}
|
||||
myDiagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, buf.toString()));
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Exception("Unsupported message type: " + messageType.name());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
myDiagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTerminatedSuccessfully() {
|
||||
return myTerminatedSuccessfully;
|
||||
}
|
||||
|
||||
private static Diagnostic.Kind convertKind(JavacRemoteProto.Message.Response.CompileMessage.Kind kind) {
|
||||
switch (kind) {
|
||||
case ERROR: return Diagnostic.Kind.ERROR;
|
||||
case WARNING: return Diagnostic.Kind.WARNING;
|
||||
case MANDATORY_WARNING: return Diagnostic.Kind.MANDATORY_WARNING;
|
||||
case NOTE: return Diagnostic.Kind.NOTE;
|
||||
default : return Diagnostic.Kind.OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
private static OutputFileObject.Kind convertKind(JavacRemoteProto.Message.Response.OutputObject.Kind kind) {
|
||||
switch (kind) {
|
||||
case CLASS: return JavaFileObject.Kind.CLASS;
|
||||
case HTML: return JavaFileObject.Kind.HTML;
|
||||
case SOURCE: return JavaFileObject.Kind.SOURCE;
|
||||
default : return JavaFileObject.Kind.OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DummyDiagnostic implements Diagnostic<JavaFileObject> {
|
||||
|
||||
private final Kind myMessageKind;
|
||||
private final JavaFileObject mySrcFileObject;
|
||||
private final JavacRemoteProto.Message.Response.CompileMessage myCompileMessage;
|
||||
|
||||
public DummyDiagnostic(final Kind messageKind, JavaFileObject srcFileObject, JavacRemoteProto.Message.Response.CompileMessage compileMessage) {
|
||||
myMessageKind = messageKind;
|
||||
mySrcFileObject = srcFileObject;
|
||||
myCompileMessage = compileMessage;
|
||||
}
|
||||
|
||||
public Kind getKind() {
|
||||
return myMessageKind;
|
||||
}
|
||||
|
||||
public JavaFileObject getSource() {
|
||||
return mySrcFileObject;
|
||||
}
|
||||
|
||||
public long getPosition() {
|
||||
return myCompileMessage.hasProblemLocationOffset()? myCompileMessage.getProblemLocationOffset() : -1;
|
||||
}
|
||||
|
||||
public long getStartPosition() {
|
||||
return myCompileMessage.hasProblemBeginOffset()? myCompileMessage.getProblemBeginOffset() : -1;
|
||||
}
|
||||
|
||||
public long getEndPosition() {
|
||||
return myCompileMessage.hasProblemEndOffset()? myCompileMessage.getProblemEndOffset() : -1;
|
||||
}
|
||||
|
||||
public long getLineNumber() {
|
||||
return myCompileMessage.hasLine()? myCompileMessage.getLine() : -1;
|
||||
}
|
||||
|
||||
public long getColumnNumber() {
|
||||
return myCompileMessage.hasColumn()? myCompileMessage.getColumn() : -1;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getMessage(Locale locale) {
|
||||
return myCompileMessage.hasText()? myCompileMessage.getText() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+163
-159
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 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.
|
||||
@@ -15,18 +15,19 @@
|
||||
*/
|
||||
package org.jetbrains.jps.javac;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.group.ChannelGroup;
|
||||
import io.netty.channel.group.ChannelGroupFuture;
|
||||
import io.netty.channel.group.DefaultChannelGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.protobuf.ProtobufDecoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufEncoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
|
||||
import io.netty.util.concurrent.ImmediateEventExecutor;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
import io.netty.util.internal.logging.Log4JLoggerFactory;
|
||||
import org.apache.log4j.ConsoleAppender;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.PatternLayout;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.api.CanceledStatus;
|
||||
import org.jetbrains.jps.builders.impl.java.JavacCompilerTool;
|
||||
@@ -37,85 +38,109 @@ import org.jetbrains.jps.service.SharedThreadPool;
|
||||
import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/22/12
|
||||
*/
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public class JavacServer {
|
||||
public static final int DEFAULT_SERVER_PORT = 7878;
|
||||
public static final String SERVER_SUCCESS_START_MESSAGE = "Javac server started successfully. Listening on port: ";
|
||||
public static final String SERVER_ERROR_START_MESSAGE = "Error starting Javac Server: ";
|
||||
public class ExternalJavacProcess {
|
||||
public static final String JPS_JAVA_COMPILING_TOOL_PROPERTY = "jps.java.compiling.tool";
|
||||
private final ChannelInitializer myChannelInitializer;
|
||||
private final EventLoopGroup myEventLoopGroup;
|
||||
private volatile ChannelFuture myConnectFuture;
|
||||
private volatile CancelHandler myCancelHandler;
|
||||
|
||||
private ChannelRegistrar myChannelRegistrar;
|
||||
|
||||
public void start(int listenPort) {
|
||||
final ServerBootstrap bootstrap = new ServerBootstrap().group(new NioEventLoopGroup(1, SharedThreadPool.getInstance())).channel(NioServerSocketChannel.class);
|
||||
bootstrap.childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
myChannelRegistrar = new ChannelRegistrar();
|
||||
final ChannelHandler compilationRequestsHandler = new CompilationRequestsHandler();
|
||||
bootstrap.childHandler(new ChannelInitializer() {
|
||||
static {
|
||||
org.apache.log4j.Logger root = org.apache.log4j.Logger.getRootLogger();
|
||||
if (!root.getAllAppenders().hasMoreElements()) {
|
||||
root.setLevel(Level.INFO);
|
||||
root.addAppender(new ConsoleAppender(new PatternLayout(PatternLayout.DEFAULT_CONVERSION_PATTERN)));
|
||||
}
|
||||
InternalLoggerFactory.setDefaultFactory(new Log4JLoggerFactory());
|
||||
}
|
||||
|
||||
public ExternalJavacProcess() {
|
||||
final JavacRemoteProto.Message msgDefaultInstance = JavacRemoteProto.Message.getDefaultInstance();
|
||||
|
||||
myEventLoopGroup = new NioEventLoopGroup(1, SharedThreadPool.getInstance());
|
||||
myChannelInitializer = new ChannelInitializer() {
|
||||
@Override
|
||||
protected void initChannel(Channel channel) throws Exception {
|
||||
channel.pipeline().addLast(myChannelRegistrar,
|
||||
new ProtobufVarint32FrameDecoder(),
|
||||
new ProtobufDecoder(JavacRemoteProto.Message.getDefaultInstance()),
|
||||
channel.pipeline().addLast(new ProtobufVarint32FrameDecoder(),
|
||||
new ProtobufDecoder(msgDefaultInstance),
|
||||
new ProtobufVarint32LengthFieldPrepender(),
|
||||
new ProtobufEncoder(),
|
||||
compilationRequestsHandler);
|
||||
new CompilationRequestsHandler()
|
||||
);
|
||||
}
|
||||
});
|
||||
myChannelRegistrar.add(bootstrap.bind(listenPort).syncUninterruptibly().channel());
|
||||
};
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
myChannelRegistrar.close().awaitUninterruptibly();
|
||||
}
|
||||
|
||||
|
||||
//static volatile long myGlobalStart;
|
||||
|
||||
public static void main(String[] args) {
|
||||
JavacServer server = null;
|
||||
try {
|
||||
int port = DEFAULT_SERVER_PORT;
|
||||
if (args.length > 0) {
|
||||
try {
|
||||
port = Integer.parseInt(args[0]);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.err.println("Error parsing port: " + e.getMessage());
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
server = new JavacServer();
|
||||
server.start(port);
|
||||
final JavacServer finalServer = server;
|
||||
Runtime.getRuntime().addShutdownHook(new Thread("Shutdown hook thread") {
|
||||
@Override
|
||||
public void run() {
|
||||
finalServer.stop();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println("Server classpath: " + System.getProperty("java.class.path"));
|
||||
System.err.println(SERVER_SUCCESS_START_MESSAGE + port);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
System.err.println(SERVER_ERROR_START_MESSAGE + e.getMessage());
|
||||
e.printStackTrace(System.err);
|
||||
//myGlobalStart = System.currentTimeMillis();
|
||||
UUID uuid = null;
|
||||
String host = null;
|
||||
int port = -1;
|
||||
if (args.length > 0) {
|
||||
try {
|
||||
if (server != null) {
|
||||
server.stop();
|
||||
}
|
||||
uuid = UUID.fromString(args[0]);
|
||||
}
|
||||
finally {
|
||||
catch (Exception e) {
|
||||
System.err.println("Error parsing session id: " + e.getMessage());
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
host = args[1];
|
||||
|
||||
try {
|
||||
port = Integer.parseInt(args[2]);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.err.println("Error parsing port: " + e.getMessage());
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.err.println("Insufficient parameters");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
final ExternalJavacProcess process = new ExternalJavacProcess();
|
||||
try {
|
||||
//final long connectStart = System.currentTimeMillis();
|
||||
if (process.connect(host, port)) {
|
||||
//final long connectEnd = System.currentTimeMillis();
|
||||
//System.err.println("Connected in " + (connectEnd - connectStart) + " ms; since start: " + (connectEnd - myGlobalStart));
|
||||
process.myConnectFuture.channel().writeAndFlush(
|
||||
JavacProtoUtil.toMessage(uuid, JavacProtoUtil.createRequestAckResponse())
|
||||
);
|
||||
}
|
||||
else {
|
||||
System.err.println("Failed to connect to parent process");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
throwable.printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
public static JavacRemoteProto.Message compile(final ChannelHandlerContext context,
|
||||
private boolean connect(final String host, final int port) throws Throwable {
|
||||
final Bootstrap bootstrap = new Bootstrap().group(myEventLoopGroup).channel(NioSocketChannel.class).handler(myChannelInitializer);
|
||||
bootstrap.option(ChannelOption.TCP_NODELAY, true).option(ChannelOption.SO_KEEPALIVE, true);
|
||||
final ChannelFuture future = bootstrap.connect(host, port).syncUninterruptibly();
|
||||
if (future.isSuccess()) {
|
||||
myConnectFuture = future;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static JavacRemoteProto.Message compile(final ChannelHandlerContext context,
|
||||
final UUID sessionId,
|
||||
List<String> options,
|
||||
Collection<File> files,
|
||||
@@ -124,6 +149,8 @@ public class JavacServer {
|
||||
Collection<File> sourcePath,
|
||||
Map<File, Set<File>> outs,
|
||||
final CanceledStatus canceledStatus) {
|
||||
//final long compileStart = System.currentTimeMillis();
|
||||
//System.err.println("Compile start; since global start: " + (compileStart - myGlobalStart));
|
||||
final DiagnosticOutputConsumer diagnostic = new DiagnosticOutputConsumer() {
|
||||
@Override
|
||||
public void javaFileLoaded(File file) {
|
||||
@@ -157,7 +184,8 @@ public class JavacServer {
|
||||
|
||||
try {
|
||||
JavaCompilingTool tool = getCompilingTool();
|
||||
final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, canceledStatus, tool);
|
||||
final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, canceledStatus,
|
||||
tool);
|
||||
return JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createBuildCompletedResponse(rc));
|
||||
}
|
||||
catch (Throwable e) {
|
||||
@@ -165,8 +193,12 @@ public class JavacServer {
|
||||
e.printStackTrace(System.err);
|
||||
return JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createFailure(e.getMessage(), e));
|
||||
}
|
||||
//finally {
|
||||
// final long compileEnd = System.currentTimeMillis();
|
||||
// System.err.println("Compiled in " + (compileEnd - compileStart) + " ms; since global start: " + (compileEnd - myGlobalStart));
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
private static JavaCompilingTool getCompilingTool() {
|
||||
String property = System.getProperty(JPS_JAVA_COMPILING_TOOL_PROPERTY);
|
||||
if (property != null) {
|
||||
@@ -178,24 +210,6 @@ public class JavacServer {
|
||||
return new JavacCompilerTool();
|
||||
}
|
||||
|
||||
private final Set<CancelHandler> myCancelHandlers = Collections.synchronizedSet(new HashSet<CancelHandler>());
|
||||
|
||||
public void cancelBuilds() {
|
||||
synchronized (myCancelHandlers) {
|
||||
for (CancelHandler handler : myCancelHandlers) {
|
||||
handler.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<File> toFiles(List<String> paths) {
|
||||
final List<File> files = new ArrayList<File>(paths.size());
|
||||
for (String path : paths) {
|
||||
files.add(new File(path));
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
private class CompilationRequestsHandler extends SimpleChannelInboundHandler<JavacRemoteProto.Message> {
|
||||
@Override
|
||||
@@ -210,52 +224,50 @@ public class JavacServer {
|
||||
final JavacRemoteProto.Message.Request request = message.getRequest();
|
||||
final JavacRemoteProto.Message.Request.Type requestType = request.getRequestType();
|
||||
if (requestType == JavacRemoteProto.Message.Request.Type.COMPILE) {
|
||||
final List<String> options = request.getOptionList();
|
||||
final List<File> files = toFiles(request.getFileList());
|
||||
final List<File> cp = toFiles(request.getClasspathList());
|
||||
final List<File> platformCp = toFiles(request.getPlatformClasspathList());
|
||||
final List<File> srcPath = toFiles(request.getSourcepathList());
|
||||
if (myCancelHandler == null) { // if not running yet
|
||||
final List<String> options = request.getOptionList();
|
||||
final List<File> files = toFiles(request.getFileList());
|
||||
final List<File> cp = toFiles(request.getClasspathList());
|
||||
final List<File> platformCp = toFiles(request.getPlatformClasspathList());
|
||||
final List<File> srcPath = toFiles(request.getSourcepathList());
|
||||
|
||||
final Map<File, Set<File>> outs = new HashMap<File, Set<File>>();
|
||||
for (JavacRemoteProto.Message.Request.OutputGroup outputGroup : request.getOutputList()) {
|
||||
final Set<File> srcRoots = new HashSet<File>();
|
||||
for (String root : outputGroup.getSourceRootList()) {
|
||||
srcRoots.add(new File(root));
|
||||
final Map<File, Set<File>> outs = new HashMap<File, Set<File>>();
|
||||
for (JavacRemoteProto.Message.Request.OutputGroup outputGroup : request.getOutputList()) {
|
||||
final Set<File> srcRoots = new HashSet<File>();
|
||||
for (String root : outputGroup.getSourceRootList()) {
|
||||
srcRoots.add(new File(root));
|
||||
}
|
||||
outs.put(new File(outputGroup.getOutputRoot()), srcRoots);
|
||||
}
|
||||
outs.put(new File(outputGroup.getOutputRoot()), srcRoots);
|
||||
|
||||
final CancelHandler cancelHandler = new CancelHandler();
|
||||
myCancelHandler = cancelHandler;
|
||||
SharedThreadPool.getInstance().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
context.channel().writeAndFlush(
|
||||
compile(context, sessionId, options, files, cp, platformCp, srcPath, outs, cancelHandler)
|
||||
).awaitUninterruptibly();
|
||||
}
|
||||
finally {
|
||||
myCancelHandler = null;
|
||||
ExternalJavacProcess.this.stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final CancelHandler cancelHandler = new CancelHandler();
|
||||
myCancelHandlers.add(cancelHandler);
|
||||
SharedThreadPool.getInstance().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
context.channel()
|
||||
.writeAndFlush(compile(context, sessionId, options, files, cp, platformCp, srcPath, outs, cancelHandler));
|
||||
}
|
||||
finally {
|
||||
myCancelHandlers.remove(cancelHandler);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (requestType == JavacRemoteProto.Message.Request.Type.CANCEL){
|
||||
cancelBuilds();
|
||||
reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createRequestAckResponse());
|
||||
cancelBuild();
|
||||
}
|
||||
else if (requestType == JavacRemoteProto.Message.Request.Type.SHUTDOWN){
|
||||
cancelBuilds();
|
||||
cancelBuild();
|
||||
new Thread("StopThread") {
|
||||
@Override
|
||||
public void run() {
|
||||
//noinspection finally
|
||||
try {
|
||||
JavacServer.this.stop();
|
||||
}
|
||||
finally {
|
||||
System.exit(0);
|
||||
}
|
||||
ExternalJavacProcess.this.stop();
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
@@ -274,46 +286,38 @@ public class JavacServer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
private static final class ChannelRegistrar extends ChannelInboundHandlerAdapter {
|
||||
private final ChannelGroup openChannels = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
|
||||
|
||||
public boolean isEmpty() {
|
||||
return openChannels.isEmpty();
|
||||
}
|
||||
|
||||
public void add(@NotNull Channel serverChannel) {
|
||||
assert serverChannel instanceof ServerChannel;
|
||||
openChannels.add(serverChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext context) throws Exception {
|
||||
// we don't need to remove channel on close - ChannelGroup do it
|
||||
openChannels.add(context.channel());
|
||||
|
||||
super.channelActive(context);
|
||||
}
|
||||
|
||||
public ChannelGroupFuture close() {
|
||||
EventLoopGroup eventLoopGroup = null;
|
||||
for (Channel channel : openChannels) {
|
||||
if (channel instanceof ServerChannel) {
|
||||
eventLoopGroup = channel.eventLoop().parent();
|
||||
break;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
try {
|
||||
//final long stopStart = System.currentTimeMillis();
|
||||
//System.err.println("Exiting. Since global start " + (stopStart - myGlobalStart));
|
||||
final ChannelFuture future = myConnectFuture;
|
||||
if (future != null) {
|
||||
future.channel().close().await();
|
||||
}
|
||||
myEventLoopGroup.shutdownGracefully(0, 15, TimeUnit.SECONDS).await();
|
||||
//final long stopEnd = System.currentTimeMillis();
|
||||
//System.err.println("Stop completed in " + (stopEnd - stopStart) + "ms; since global start: " + ((stopEnd - myGlobalStart)));
|
||||
System.exit(0);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
ChannelGroupFuture future;
|
||||
try {
|
||||
future = openChannels.close();
|
||||
}
|
||||
finally {
|
||||
assert eventLoopGroup != null;
|
||||
eventLoopGroup.shutdownGracefully();
|
||||
}
|
||||
return future;
|
||||
private static List<File> toFiles(List<String> paths) {
|
||||
final List<File> files = new ArrayList<File>(paths.size());
|
||||
for (String path : paths) {
|
||||
files.add(new File(path));
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
public void cancelBuild() {
|
||||
final CancelHandler cancelHandler = myCancelHandler;
|
||||
if (cancelHandler != null) {
|
||||
cancelHandler.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,4 +336,4 @@ public class JavacServer {
|
||||
return myIsCanceled;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.jps.javac;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.group.ChannelGroup;
|
||||
import io.netty.channel.group.ChannelGroupFuture;
|
||||
import io.netty.channel.group.DefaultChannelGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.protobuf.ProtobufDecoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufEncoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
|
||||
import io.netty.util.AttributeKey;
|
||||
import io.netty.util.concurrent.ImmediateEventExecutor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.builders.java.JavaCompilingTool;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.GlobalContextKey;
|
||||
import org.jetbrains.jps.incremental.Utils;
|
||||
import org.jetbrains.jps.model.JpsProject;
|
||||
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
|
||||
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration;
|
||||
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerOptions;
|
||||
import org.jetbrains.jps.service.SharedThreadPool;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/22/12
|
||||
*/
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public class ExternalJavacServer {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.javac.ExternalJavacServer");
|
||||
public static final GlobalContextKey<ExternalJavacServer> KEY = GlobalContextKey.create("_external_javac_server_");
|
||||
|
||||
public static final int DEFAULT_SERVER_PORT = 7878;
|
||||
private static final AttributeKey<JavacProcessDescriptor> SESSION_DESCRIPTOR = AttributeKey.valueOf("ExternalJavacServer.JavacProcessDescriptor");
|
||||
|
||||
private ChannelRegistrar myChannelRegistrar;
|
||||
private final Map<UUID, JavacProcessDescriptor> myMessageHandlers = new HashMap<UUID, JavacProcessDescriptor>();
|
||||
private int myListenPort = DEFAULT_SERVER_PORT;
|
||||
|
||||
public void start(int listenPort) {
|
||||
final ServerBootstrap bootstrap = new ServerBootstrap().group(new NioEventLoopGroup(1, SharedThreadPool.getInstance())).channel(NioServerSocketChannel.class);
|
||||
bootstrap.childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
myChannelRegistrar = new ChannelRegistrar();
|
||||
final ChannelHandler compilationRequestsHandler = new CompilationRequestsHandler();
|
||||
bootstrap.childHandler(new ChannelInitializer() {
|
||||
@Override
|
||||
protected void initChannel(Channel channel) throws Exception {
|
||||
channel.pipeline().addLast(myChannelRegistrar,
|
||||
new ProtobufVarint32FrameDecoder(),
|
||||
new ProtobufDecoder(JavacRemoteProto.Message.getDefaultInstance()),
|
||||
new ProtobufVarint32LengthFieldPrepender(),
|
||||
new ProtobufEncoder(),
|
||||
compilationRequestsHandler);
|
||||
}
|
||||
});
|
||||
myChannelRegistrar.add(bootstrap.bind(listenPort).syncUninterruptibly().channel());
|
||||
myListenPort = listenPort;
|
||||
}
|
||||
|
||||
private static int getExternalJavacHeapSize(CompileContext context) {
|
||||
final JpsProject project = context.getProjectDescriptor().getProject();
|
||||
final JpsJavaCompilerConfiguration config = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project);
|
||||
final JpsJavaCompilerOptions options = config.getCurrentCompilerOptions();
|
||||
return options.MAXIMUM_HEAP_SIZE;
|
||||
}
|
||||
|
||||
|
||||
public boolean forkJavac(CompileContext context, List<String> options,
|
||||
List<String> vmOptions, Collection<File> files,
|
||||
Collection<File> classpath,
|
||||
Collection<File> platformCp,
|
||||
Collection<File> sourcePath,
|
||||
Map<File, Set<File>> outs,
|
||||
DiagnosticOutputConsumer diagnosticSink,
|
||||
OutputFileConsumer outputSink,
|
||||
final String javaHome, final JavaCompilingTool compilingTool) {
|
||||
final ExternalJavacMessageHandler rh = new ExternalJavacMessageHandler(diagnosticSink, outputSink, getEncodingName(options));
|
||||
final JavacRemoteProto.Message.Request request = JavacProtoUtil.createCompilationRequest(options, files, classpath, platformCp, sourcePath, outs);
|
||||
final UUID uuid = UUID.randomUUID();
|
||||
final JavacProcessDescriptor processDescriptor = new JavacProcessDescriptor(uuid, rh, request);
|
||||
synchronized (myMessageHandlers) {
|
||||
myMessageHandlers.put(uuid, processDescriptor);
|
||||
}
|
||||
try {
|
||||
final JavacServerBootstrap.ExternalJavacProcessHandler processHandler = JavacServerBootstrap.launchExternalJavacProcess(
|
||||
uuid, javaHome, getExternalJavacHeapSize(context), myListenPort, Utils.getSystemRoot(), vmOptions, compilingTool
|
||||
);
|
||||
|
||||
while (!processDescriptor.waitFor(300L)) {
|
||||
if (processHandler.isProcessTerminated() && processDescriptor.channel == null && processHandler.getExitCode() != 0) {
|
||||
// process terminated abnormally and no communication took place
|
||||
processDescriptor.setDone();
|
||||
break;
|
||||
}
|
||||
if (context.getCancelStatus().isCanceled()) {
|
||||
processDescriptor.cancelBuild();
|
||||
}
|
||||
}
|
||||
|
||||
return rh.isTerminatedSuccessfully();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.info(e);
|
||||
diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage()));
|
||||
}
|
||||
finally {
|
||||
unregisterMessageHandler(uuid);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void unregisterMessageHandler(UUID uuid) {
|
||||
final JavacProcessDescriptor descriptor;
|
||||
synchronized (myMessageHandlers) {
|
||||
descriptor = myMessageHandlers.remove(uuid);
|
||||
}
|
||||
if (descriptor != null) {
|
||||
descriptor.setDone();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEncodingName(List<String> options) {
|
||||
boolean found = false;
|
||||
for (String option : options) {
|
||||
if (found) {
|
||||
return option;
|
||||
}
|
||||
if ("-encoding".equalsIgnoreCase(option)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
myChannelRegistrar.close().awaitUninterruptibly();
|
||||
}
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
private class CompilationRequestsHandler extends SimpleChannelInboundHandler<JavacRemoteProto.Message> {
|
||||
@Override
|
||||
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
|
||||
JavacProcessDescriptor descriptor = ctx.attr(SESSION_DESCRIPTOR).get();
|
||||
if (descriptor != null) {
|
||||
descriptor.setDone();
|
||||
}
|
||||
super.channelUnregistered(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead0(final ChannelHandlerContext context, JavacRemoteProto.Message message) throws Exception {
|
||||
JavacProcessDescriptor descriptor = context.attr(SESSION_DESCRIPTOR).get();
|
||||
|
||||
UUID sessionId;
|
||||
if (descriptor == null) {
|
||||
// this is the first message for this session, so fill session data with missing info
|
||||
sessionId = JavacProtoUtil.fromProtoUUID(message.getSessionId());
|
||||
|
||||
descriptor = myMessageHandlers.get(sessionId);
|
||||
if (descriptor != null) {
|
||||
descriptor.channel = context.channel();
|
||||
context.attr(SESSION_DESCRIPTOR).set(descriptor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
sessionId = descriptor.sessionId;
|
||||
}
|
||||
|
||||
final ExternalJavacMessageHandler handler = descriptor != null? descriptor.handler : null;
|
||||
|
||||
final JavacRemoteProto.Message.Type messageType = message.getMessageType();
|
||||
|
||||
JavacRemoteProto.Message reply = null;
|
||||
try {
|
||||
if (messageType == JavacRemoteProto.Message.Type.RESPONSE) {
|
||||
final JavacRemoteProto.Message.Response response = message.getResponse();
|
||||
final JavacRemoteProto.Message.Response.Type responseType = response.getResponseType();
|
||||
if (handler != null) {
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.REQUEST_ACK) {
|
||||
final JavacRemoteProto.Message.Request request = descriptor.request;
|
||||
if (request != null) {
|
||||
reply = JavacProtoUtil.toMessage(sessionId, request);
|
||||
descriptor.request = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
final boolean terminateOk = handler.handleMessage(message);
|
||||
if (terminateOk) {
|
||||
descriptor.setDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createCancelRequest());
|
||||
}
|
||||
}
|
||||
else {
|
||||
reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createFailure("Unsupported message: " + messageType.name(), null));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (reply != null) {
|
||||
context.channel().writeAndFlush(reply);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
private static final class ChannelRegistrar extends ChannelInboundHandlerAdapter {
|
||||
private final ChannelGroup openChannels = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
|
||||
|
||||
public boolean isEmpty() {
|
||||
return openChannels.isEmpty();
|
||||
}
|
||||
|
||||
public void add(@NotNull Channel serverChannel) {
|
||||
assert serverChannel instanceof ServerChannel;
|
||||
openChannels.add(serverChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext context) throws Exception {
|
||||
// we don't need to remove channel on close - ChannelGroup do it
|
||||
openChannels.add(context.channel());
|
||||
super.channelActive(context);
|
||||
}
|
||||
|
||||
public ChannelGroupFuture close() {
|
||||
EventLoopGroup eventLoopGroup = null;
|
||||
for (Channel channel : openChannels) {
|
||||
if (channel instanceof ServerChannel) {
|
||||
eventLoopGroup = channel.eventLoop().parent();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ChannelGroupFuture future;
|
||||
try {
|
||||
future = openChannels.close();
|
||||
}
|
||||
finally {
|
||||
assert eventLoopGroup != null;
|
||||
eventLoopGroup.shutdownGracefully(0, 15, TimeUnit.SECONDS);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
||||
private static class JavacProcessDescriptor {
|
||||
@NotNull
|
||||
final UUID sessionId;
|
||||
@NotNull
|
||||
final ExternalJavacMessageHandler handler;
|
||||
volatile JavacRemoteProto.Message.Request request;
|
||||
volatile Channel channel;
|
||||
private final Semaphore myDone = new Semaphore();
|
||||
|
||||
public JavacProcessDescriptor(@NotNull UUID sessionId, @NotNull ExternalJavacMessageHandler handler, @NotNull JavacRemoteProto.Message.Request request) {
|
||||
this.sessionId = sessionId;
|
||||
this.handler = handler;
|
||||
this.request = request;
|
||||
myDone.down();
|
||||
}
|
||||
|
||||
public void cancelBuild() {
|
||||
if (channel != null) {
|
||||
channel.writeAndFlush(JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createCancelRequest()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setDone() {
|
||||
myDone.up();
|
||||
}
|
||||
|
||||
|
||||
public boolean waitFor(long timeout) {
|
||||
return myDone.waitFor(timeout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,11 +20,9 @@ import com.intellij.execution.process.ProcessAdapter;
|
||||
import com.intellij.execution.process.ProcessEvent;
|
||||
import com.intellij.execution.process.ProcessOutputTypes;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import org.jetbrains.jps.builders.java.JavaCompilingTool;
|
||||
import org.jetbrains.jps.cmdline.ClasspathBootstrap;
|
||||
import org.jetbrains.jps.service.SharedThreadPool;
|
||||
@@ -32,6 +30,7 @@ import org.jetbrains.jps.service.SharedThreadPool;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
@@ -40,15 +39,15 @@ import java.util.concurrent.Future;
|
||||
*/
|
||||
public class JavacServerBootstrap {
|
||||
|
||||
public static BaseOSProcessHandler launchJavacServer(String sdkHomePath,
|
||||
int heapSize,
|
||||
int port,
|
||||
File workingDir,
|
||||
List<String> vmOptions,
|
||||
JavaCompilingTool compilingTool) throws Exception {
|
||||
public static ExternalJavacProcessHandler launchExternalJavacProcess(UUID uuid, String sdkHomePath,
|
||||
int heapSize,
|
||||
int port,
|
||||
File workingDir,
|
||||
List<String> vmOptions,
|
||||
JavaCompilingTool compilingTool) throws Exception {
|
||||
final List<String> cmdLine = new ArrayList<String>();
|
||||
appendParam(cmdLine, getVMExecutablePath(sdkHomePath));
|
||||
appendParam(cmdLine, "-XX:MaxPermSize=150m");
|
||||
//appendParam(cmdLine, "-XX:MaxPermSize=150m");
|
||||
//appendParam(cmdLine, "-XX:ReservedCodeCacheSize=64m");
|
||||
appendParam(cmdLine, "-Djava.awt.headless=true");
|
||||
final int xms = heapSize / 2;
|
||||
@@ -59,7 +58,7 @@ public class JavacServerBootstrap {
|
||||
|
||||
// debugging
|
||||
//appendParam(cmdLine, "-XX:+HeapDumpOnOutOfMemoryError");
|
||||
//appendParam(cmdLine, "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5009");
|
||||
//appendParam(cmdLine, "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5009");
|
||||
|
||||
// javac's VM should use the same default locale that IDEA uses in order for javac to print messages in 'correct' language
|
||||
final String encoding = System.getProperty("file.encoding");
|
||||
@@ -83,18 +82,20 @@ public class JavacServerBootstrap {
|
||||
appendParam(cmdLine, "-Duser.region=" + region);
|
||||
}
|
||||
|
||||
appendParam(cmdLine, "-D" + JavacServer.JPS_JAVA_COMPILING_TOOL_PROPERTY + "=" + compilingTool.getId());
|
||||
appendParam(cmdLine, "-D" + ExternalJavacProcess.JPS_JAVA_COMPILING_TOOL_PROPERTY + "=" + compilingTool.getId());
|
||||
|
||||
// this will disable standard extensions to ensure javac is loaded from the right tools.jar
|
||||
appendParam(cmdLine, "-Djava.ext.dirs=");
|
||||
|
||||
|
||||
appendParam(cmdLine, "-Dlog4j.defaultInitOverride=true");
|
||||
|
||||
for (String option : vmOptions) {
|
||||
appendParam(cmdLine, option);
|
||||
}
|
||||
|
||||
appendParam(cmdLine, "-classpath");
|
||||
|
||||
final List<File> cp = ClasspathBootstrap.getJavacServerClasspath(sdkHomePath, compilingTool);
|
||||
final List<File> cp = ClasspathBootstrap.getExternalJavacProcessClasspath(sdkHomePath, compilingTool);
|
||||
final StringBuilder classpath = new StringBuilder();
|
||||
for (File file : cp) {
|
||||
if (classpath.length() > 0) {
|
||||
@@ -104,7 +105,9 @@ public class JavacServerBootstrap {
|
||||
}
|
||||
appendParam(cmdLine, classpath.toString());
|
||||
|
||||
appendParam(cmdLine, org.jetbrains.jps.javac.JavacServer.class.getName());
|
||||
appendParam(cmdLine, org.jetbrains.jps.javac.ExternalJavacProcess.class.getName());
|
||||
appendParam(cmdLine, uuid.toString());
|
||||
appendParam(cmdLine, "127.0.0.1");
|
||||
appendParam(cmdLine, Integer.toString(port));
|
||||
|
||||
workingDir.mkdirs();
|
||||
@@ -115,68 +118,31 @@ public class JavacServerBootstrap {
|
||||
builder.directory(workingDir);
|
||||
|
||||
final Process process = builder.start();
|
||||
final BaseOSProcessHandler processHandler = new BaseOSProcessHandler(process, null, null) {
|
||||
@Override
|
||||
protected Future<?> executeOnPooledThread(Runnable task) {
|
||||
return SharedThreadPool.getInstance().executeOnPooledThread(task);
|
||||
}
|
||||
};
|
||||
configureProcessHandler(processHandler);
|
||||
|
||||
return processHandler;
|
||||
}
|
||||
|
||||
private static void configureProcessHandler(final BaseOSProcessHandler processHandler) throws Exception {
|
||||
final ExternalJavacProcessHandler processHandler = new ExternalJavacProcessHandler(process);
|
||||
processHandler.addProcessListener(new ProcessAdapter() {
|
||||
@Override
|
||||
public void processTerminated(ProcessEvent event) {
|
||||
processHandler.setExitCode(event.getExitCode());
|
||||
}
|
||||
|
||||
public void onTextAvailable(ProcessEvent event, Key outputType) {
|
||||
final String text = event.getText();
|
||||
if (!StringUtil.isEmptyOrSpaces(text)) {
|
||||
if (outputType == ProcessOutputTypes.STDOUT) {
|
||||
System.out.print("JAVAC_SERVER: " + text);
|
||||
System.out.print("JAVAC_PROCESS: " + text);
|
||||
}
|
||||
else if (outputType == ProcessOutputTypes.STDERR){
|
||||
System.err.print("JAVAC_SERVER: " + text);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
final Semaphore semaphore = new Semaphore();
|
||||
semaphore.down();
|
||||
final Ref<String> serverStartMessage = new Ref<String>(null);
|
||||
processHandler.addProcessListener(new ProcessAdapter() {
|
||||
public void processTerminated(ProcessEvent event) {
|
||||
try {
|
||||
processHandler.removeProcessListener(this);
|
||||
}
|
||||
finally {
|
||||
semaphore.up();
|
||||
}
|
||||
}
|
||||
|
||||
public void onTextAvailable(ProcessEvent event, Key outputType) {
|
||||
if (outputType == ProcessOutputTypes.STDERR) {
|
||||
final String text = event.getText();
|
||||
if (text != null && (text.contains(JavacServer.SERVER_SUCCESS_START_MESSAGE) || text.contains(JavacServer.SERVER_ERROR_START_MESSAGE))) {
|
||||
try {
|
||||
processHandler.removeProcessListener(this);
|
||||
serverStartMessage.set(text);
|
||||
}
|
||||
finally {
|
||||
semaphore.up();
|
||||
}
|
||||
else if (outputType == ProcessOutputTypes.STDERR) {
|
||||
System.err.print("JAVAC_PROCESS: " + text);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
processHandler.startNotify();
|
||||
semaphore.waitFor();
|
||||
|
||||
final String startupMsg = serverStartMessage.get();
|
||||
if (startupMsg == null || !startupMsg.contains(JavacServer.SERVER_SUCCESS_START_MESSAGE)) {
|
||||
throw new Exception("Server startup failed: " + startupMsg);
|
||||
}
|
||||
return processHandler;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void appendParam(List<String> cmdLine, String param) {
|
||||
if (SystemInfo.isWindows) {
|
||||
if (param.contains("\"")) {
|
||||
@@ -192,4 +158,25 @@ public class JavacServerBootstrap {
|
||||
public static String getVMExecutablePath(String sdkHome) {
|
||||
return sdkHome + "/bin/java";
|
||||
}
|
||||
|
||||
public static class ExternalJavacProcessHandler extends BaseOSProcessHandler {
|
||||
private volatile int myExitCode;
|
||||
|
||||
ExternalJavacProcessHandler(Process process) {
|
||||
super(process, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Future<?> executeOnPooledThread(Runnable task) {
|
||||
return SharedThreadPool.getInstance().executeOnPooledThread(task);
|
||||
}
|
||||
|
||||
void setExitCode(int exitCode) {
|
||||
myExitCode = exitCode;
|
||||
}
|
||||
|
||||
public int getExitCode() {
|
||||
return myExitCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-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.jps.javac;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.api.RequestFuture;
|
||||
import org.jetbrains.jps.client.SimpleProtobufClient;
|
||||
import org.jetbrains.jps.client.UUIDGetter;
|
||||
import org.jetbrains.jps.service.SharedThreadPool;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/22/12
|
||||
*/
|
||||
public class JavacServerClient extends SimpleProtobufClient<JavacServerResponseHandler>{
|
||||
|
||||
public JavacServerClient() {
|
||||
super(JavacRemoteProto.Message.getDefaultInstance(), SharedThreadPool.getInstance(), new UUIDGetter() {
|
||||
@Override
|
||||
@NotNull
|
||||
public UUID getSessionUUID(@NotNull JavacRemoteProto.Message message) {
|
||||
final JavacRemoteProto.Message.UUID uuid = message.getSessionId();
|
||||
return new UUID(uuid.getMostSigBits(), uuid.getLeastSigBits());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public RequestFuture<JavacServerResponseHandler> sendCompileRequest(List<String> options, Collection<File> files, Collection<File> classpath, Collection<File> platformCp, Collection<File> sourcePath, Map<File, Set<File>> outs, DiagnosticOutputConsumer diagnosticSink, OutputFileConsumer outputSink) {
|
||||
final JavacServerResponseHandler rh = new JavacServerResponseHandler(diagnosticSink, outputSink, getEncodingName(options));
|
||||
final JavacRemoteProto.Message.Request request = JavacProtoUtil.createCompilationRequest(options, files, classpath, platformCp, sourcePath, outs);
|
||||
return sendRequest(request, rh, new RequestFuture.CancelAction<JavacServerResponseHandler>() {
|
||||
@Override
|
||||
public void cancel(RequestFuture<JavacServerResponseHandler> javacServerResponseHandlerRequestFuture) throws Exception {
|
||||
sendRequest(JavacProtoUtil.createCancelRequest(), null, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public RequestFuture sendShutdownRequest() {
|
||||
return sendRequest(JavacProtoUtil.createShutdownRequest(), null, null);
|
||||
}
|
||||
|
||||
private RequestFuture<JavacServerResponseHandler> sendRequest(final JavacRemoteProto.Message.Request request, final JavacServerResponseHandler responseHandler, final RequestFuture.CancelAction<JavacServerResponseHandler> cancelAction) {
|
||||
final UUID requestId = UUID.randomUUID();
|
||||
return sendMessage(requestId, JavacProtoUtil.toMessage(requestId, request), responseHandler, cancelAction);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEncodingName(List<String> options) {
|
||||
boolean found = false;
|
||||
for (String option : options) {
|
||||
if (found) {
|
||||
return option;
|
||||
}
|
||||
if ("-encoding".equalsIgnoreCase(option)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-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.jps.javac;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.MessageLite;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.client.ProtobufResponseHandler;
|
||||
import org.jetbrains.jps.incremental.BinaryContent;
|
||||
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaFileObject;
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/22/12
|
||||
*/
|
||||
public class JavacServerResponseHandler implements ProtobufResponseHandler{
|
||||
private final DiagnosticOutputConsumer myDiagnosticSink;
|
||||
private final OutputFileConsumer myOutputSink;
|
||||
@Nullable
|
||||
private final String myEncodingName;
|
||||
private volatile boolean myTerminatedSuccessfully;
|
||||
|
||||
public JavacServerResponseHandler(DiagnosticOutputConsumer diagnosticSink, OutputFileConsumer outputSink, @Nullable final String encodingName) {
|
||||
myDiagnosticSink = diagnosticSink;
|
||||
myOutputSink = outputSink;
|
||||
myEncodingName = encodingName;
|
||||
}
|
||||
|
||||
public boolean handleMessage(MessageLite message) throws Exception {
|
||||
final JavacRemoteProto.Message msg = (JavacRemoteProto.Message)message;
|
||||
final JavacRemoteProto.Message.Type messageType = msg.getMessageType();
|
||||
|
||||
if (messageType == JavacRemoteProto.Message.Type.RESPONSE) {
|
||||
final JavacRemoteProto.Message.Response response = msg.getResponse();
|
||||
final JavacRemoteProto.Message.Response.Type responseType = response.getResponseType();
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.BUILD_MESSAGE) {
|
||||
final JavacRemoteProto.Message.Response.CompileMessage compileMessage = response.getCompileMessage();
|
||||
final JavacRemoteProto.Message.Response.CompileMessage.Kind messageKind = compileMessage.getKind();
|
||||
|
||||
if (messageKind == JavacRemoteProto.Message.Response.CompileMessage.Kind.STD_OUT) {
|
||||
if (compileMessage.hasText()) {
|
||||
myDiagnosticSink.outputLineAvailable(compileMessage.getText());
|
||||
}
|
||||
}
|
||||
else {
|
||||
final String sourceUri = compileMessage.hasSourceUri()? compileMessage.getSourceUri() : null;
|
||||
final JavaFileObject srcFileObject = sourceUri != null? new DummyJavaFileObject(URI.create(sourceUri)) : null;
|
||||
myDiagnosticSink.report(new DummyDiagnostic(convertKind(messageKind), srcFileObject, compileMessage));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.OUTPUT_OBJECT) {
|
||||
final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject();
|
||||
final JavacRemoteProto.Message.Response.OutputObject.Kind kind = outputObject.getKind();
|
||||
|
||||
final String outputRoot = outputObject.hasOutputRoot()? outputObject.getOutputRoot() : null;
|
||||
final File outputRootFile = outputRoot != null? new File(outputRoot) : null;
|
||||
|
||||
final BinaryContent fileObjectContent;
|
||||
final ByteString content = outputObject.hasContent()? outputObject.getContent() : null;
|
||||
if (content != null) {
|
||||
final byte[] bytes = content.toByteArray();
|
||||
fileObjectContent = new BinaryContent(bytes, 0, bytes.length);
|
||||
}
|
||||
else {
|
||||
fileObjectContent = null;
|
||||
}
|
||||
|
||||
final String sourceUri = outputObject.hasSourceUri()? outputObject.getSourceUri() : null;
|
||||
final URI srcUri = sourceUri != null? URI.create(sourceUri) : null;
|
||||
final OutputFileObject fileObject = new OutputFileObject(
|
||||
null,
|
||||
outputRootFile,
|
||||
outputObject.hasRelativePath()? outputObject.getRelativePath() : null,
|
||||
new File(outputObject.getFilePath()),
|
||||
convertKind(kind),
|
||||
outputObject.hasClassName()? outputObject.getClassName() : null,
|
||||
srcUri,
|
||||
myEncodingName, fileObjectContent
|
||||
);
|
||||
|
||||
myOutputSink.save(fileObject);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.SRC_FILE_LOADED) {
|
||||
final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject();
|
||||
final File file = new File(outputObject.getFilePath());
|
||||
myDiagnosticSink.javaFileLoaded(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.CLASS_DATA) {
|
||||
final JavacRemoteProto.Message.Response.ClassData data = response.getClassData();
|
||||
final String className = data.getClassName();
|
||||
final Collection<String> imports = data.getImportStatementList();
|
||||
final Collection<String> staticImports = data.getStaticImportList();
|
||||
myDiagnosticSink.registerImports(className, imports, staticImports);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.BUILD_COMPLETED) {
|
||||
if (response.hasCompletionStatus()) {
|
||||
myTerminatedSuccessfully = response.getCompletionStatus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.REQUEST_ACK) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Exception("Unsupported response type: " + responseType.name());
|
||||
}
|
||||
|
||||
if (messageType == JavacRemoteProto.Message.Type.FAILURE) {
|
||||
final JavacRemoteProto.Message.Failure failure = msg.getFailure();
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
if (failure.hasDescription()) {
|
||||
buf.append(failure.getDescription());
|
||||
}
|
||||
if (failure.hasStacktrace()) {
|
||||
if (buf.length() > 0) {
|
||||
buf.append("\n");
|
||||
}
|
||||
buf.append(failure.getStacktrace());
|
||||
}
|
||||
myDiagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, buf.toString()));
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Exception("Unsupported message type: " + messageType.name());
|
||||
}
|
||||
|
||||
public boolean isTerminatedSuccessfully() {
|
||||
return myTerminatedSuccessfully;
|
||||
}
|
||||
|
||||
private static Diagnostic.Kind convertKind(JavacRemoteProto.Message.Response.CompileMessage.Kind kind) {
|
||||
switch (kind) {
|
||||
case ERROR: return Diagnostic.Kind.ERROR;
|
||||
case WARNING: return Diagnostic.Kind.WARNING;
|
||||
case MANDATORY_WARNING: return Diagnostic.Kind.MANDATORY_WARNING;
|
||||
case NOTE: return Diagnostic.Kind.NOTE;
|
||||
default : return Diagnostic.Kind.OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
private static OutputFileObject.Kind convertKind(JavacRemoteProto.Message.Response.OutputObject.Kind kind) {
|
||||
switch (kind) {
|
||||
case CLASS: return JavaFileObject.Kind.CLASS;
|
||||
case HTML: return JavaFileObject.Kind.HTML;
|
||||
case SOURCE: return JavaFileObject.Kind.SOURCE;
|
||||
default : return JavaFileObject.Kind.OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
public void sessionTerminated() {
|
||||
}
|
||||
|
||||
private static class DummyDiagnostic implements Diagnostic<JavaFileObject> {
|
||||
|
||||
private final Kind myMessageKind;
|
||||
private final JavaFileObject mySrcFileObject;
|
||||
private final JavacRemoteProto.Message.Response.CompileMessage myCompileMessage;
|
||||
|
||||
public DummyDiagnostic(final Kind messageKind, JavaFileObject srcFileObject, JavacRemoteProto.Message.Response.CompileMessage compileMessage) {
|
||||
myMessageKind = messageKind;
|
||||
mySrcFileObject = srcFileObject;
|
||||
myCompileMessage = compileMessage;
|
||||
}
|
||||
|
||||
public Kind getKind() {
|
||||
return myMessageKind;
|
||||
}
|
||||
|
||||
public JavaFileObject getSource() {
|
||||
return mySrcFileObject;
|
||||
}
|
||||
|
||||
public long getPosition() {
|
||||
return myCompileMessage.hasProblemLocationOffset()? myCompileMessage.getProblemLocationOffset() : -1;
|
||||
}
|
||||
|
||||
public long getStartPosition() {
|
||||
return myCompileMessage.hasProblemBeginOffset()? myCompileMessage.getProblemBeginOffset() : -1;
|
||||
}
|
||||
|
||||
public long getEndPosition() {
|
||||
return myCompileMessage.hasProblemEndOffset()? myCompileMessage.getProblemEndOffset() : -1;
|
||||
}
|
||||
|
||||
public long getLineNumber() {
|
||||
return myCompileMessage.hasLine()? myCompileMessage.getLine() : -1;
|
||||
}
|
||||
|
||||
public long getColumnNumber() {
|
||||
return myCompileMessage.hasColumn()? myCompileMessage.getColumn() : -1;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getMessage(Locale locale) {
|
||||
return myCompileMessage.hasText()? myCompileMessage.getText() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,5 +19,5 @@ package org.jetbrains.jps.model.java;
|
||||
* @author nik
|
||||
*/
|
||||
public enum LanguageLevel {
|
||||
JDK_1_3, JDK_1_4, JDK_1_5, JDK_1_6, JDK_1_7, JDK_1_8
|
||||
JDK_1_3, JDK_1_4, JDK_1_5, JDK_1_6, JDK_1_7, JDK_1_8, JDK_1_9
|
||||
}
|
||||
|
||||
@@ -16,5 +16,12 @@
|
||||
package com.intellij.openapi.components;
|
||||
|
||||
public enum RoamingType {
|
||||
DISABLED, PER_PLATFORM, GLOBAL, PER_USER
|
||||
DISABLED,
|
||||
PER_PLATFORM,
|
||||
@Deprecated
|
||||
/**
|
||||
* Use {@link #PER_USER} instead
|
||||
*/
|
||||
GLOBAL,
|
||||
PER_USER
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.util.List;
|
||||
* @author peter
|
||||
*/
|
||||
public class DocumentationProviderEx implements DocumentationProvider {
|
||||
@Nullable
|
||||
@Override
|
||||
public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
|
||||
return null;
|
||||
|
||||
@@ -40,7 +40,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
public class PsiUtilBase extends PsiUtilCore implements PsiEditorUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.util.PsiUtilBase");
|
||||
@@ -235,6 +237,9 @@ public class PsiUtilBase extends PsiUtilCore implements PsiEditorUtil {
|
||||
*/
|
||||
@Nullable
|
||||
public static Editor findEditor(@NotNull PsiElement element) {
|
||||
if (!EventQueue.isDispatchThread()) {
|
||||
LOG.warn("Invoke findEditor() from EDT only. Otherwise, it causes deadlocks.");
|
||||
}
|
||||
PsiFile psiFile = element.getContainingFile();
|
||||
VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element);
|
||||
if (virtualFile == null) {
|
||||
|
||||
@@ -29,11 +29,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
@State(
|
||||
name = "RecentDirectoryProjectsManager",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages = {
|
||||
@Storage(
|
||||
file = StoragePathMacros.APP_CONFIG + "/other.xml"
|
||||
)}
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", roamingType = RoamingType.DISABLED)}
|
||||
)
|
||||
public class RecentDirectoryProjectsManagerEx extends RecentDirectoryProjectsManager {
|
||||
public RecentDirectoryProjectsManagerEx(MessageBus messageBus) {
|
||||
|
||||
+11
-17
@@ -32,22 +32,22 @@ import com.intellij.util.ArrayUtil;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jdom.Attribute;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IModuleStore {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.ModuleStoreImpl");
|
||||
@NonNls private static final String MODULE_FILE_MACRO = "MODULE_FILE";
|
||||
|
||||
private final ModuleImpl myModule;
|
||||
|
||||
public static final String DEFAULT_STATE_STORAGE = "$" + MODULE_FILE_MACRO + "$";
|
||||
|
||||
public static final String DEFAULT_STATE_STORAGE = "$MODULE_FILE$";
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
public ModuleStoreImpl(final ComponentManagerImpl componentManager, final ModuleImpl module) {
|
||||
@@ -56,8 +56,8 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
|
||||
}
|
||||
|
||||
@Override
|
||||
protected XmlElementStorage getMainStorage() {
|
||||
final XmlElementStorage storage = (XmlElementStorage)getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE);
|
||||
protected FileBasedStorage getMainStorage() {
|
||||
FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getStateStorage(DEFAULT_STATE_STORAGE, RoamingType.PER_USER);
|
||||
assert storage != null;
|
||||
return storage;
|
||||
}
|
||||
@@ -186,31 +186,25 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
|
||||
LocalFileSystem.getInstance().refreshAndFindFileByPath(path);
|
||||
final StateStorageManager storageManager = getStateStorageManager();
|
||||
storageManager.clearStateStorage(DEFAULT_STATE_STORAGE);
|
||||
storageManager.addMacro(MODULE_FILE_MACRO, path);
|
||||
storageManager.addMacro(DEFAULT_STATE_STORAGE, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public VirtualFile getModuleFile() {
|
||||
final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE);
|
||||
assert storage != null;
|
||||
return storage.getVirtualFile();
|
||||
return getMainStorage().getVirtualFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getModuleFilePath() {
|
||||
final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE);
|
||||
assert storage != null;
|
||||
return storage.getFilePath();
|
||||
return getMainStorage().getFilePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getModuleFileName() {
|
||||
final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE);
|
||||
assert storage != null;
|
||||
return storage.getFileName();
|
||||
return getMainStorage().getFile().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-6
@@ -41,12 +41,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@State(
|
||||
name="ProjectJdkTable",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages= {
|
||||
@Storage(
|
||||
file = StoragePathMacros.APP_CONFIG + "/jdk.table.xml"
|
||||
)}
|
||||
name = "ProjectJdkTable",
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/jdk.table.xml", roamingType = RoamingType.DISABLED)}
|
||||
)
|
||||
public class ProjectJdkTableImpl extends ProjectJdkTable implements PersistentStateComponent<Element>, ExportableComponent {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.impl.ProjectJdkTableImpl");
|
||||
|
||||
+1
-4
@@ -27,10 +27,7 @@ import java.io.File;
|
||||
*/
|
||||
@State(
|
||||
name = "libraryTable",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages = {
|
||||
@Storage( file = StoragePathMacros.APP_CONFIG + "/applicationLibraries.xml")
|
||||
}
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/applicationLibraries.xml", roamingType = RoamingType.DISABLED)}
|
||||
)
|
||||
public class ExportableApplicationLibraryTable extends ApplicationLibraryTable implements ExportableComponent {
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -102,7 +102,7 @@ public class ClasspathStorage implements StateStorage {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T getState(final Object component, final String componentName, Class<T> stateClass, @Nullable T mergeInto)
|
||||
public <T> T getState(final Object component, @NotNull final String componentName, Class<T> stateClass, @Nullable T mergeInto)
|
||||
throws StateStorageException {
|
||||
assert component instanceof ModuleRootManager;
|
||||
assert componentName.equals("NewModuleRootManager");
|
||||
@@ -142,7 +142,7 @@ public class ClasspathStorage implements StateStorage {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData)
|
||||
public boolean hasState(final Object component, @NotNull final String componentName, final Class<?> aClass, final boolean reloadData)
|
||||
throws StateStorageException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -63,11 +63,7 @@ import java.util.concurrent.locks.Lock;
|
||||
|
||||
@State(
|
||||
name = "FileBasedIndex",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages = {
|
||||
@Storage(
|
||||
file = StoragePathMacros.APP_CONFIG + "/stubIndex.xml")
|
||||
}
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/stubIndex.xml", roamingType = RoamingType.DISABLED)}
|
||||
)
|
||||
public class StubIndexImpl extends StubIndex implements ApplicationComponent, PersistentStateComponent<StubIndexState> {
|
||||
private static final AtomicReference<Boolean> ourForcedClean = new AtomicReference<Boolean>(null);
|
||||
@@ -109,7 +105,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
|
||||
|
||||
myStubProcessingHelper = new StubProcessingHelper(fileBasedIndex);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public static StubIndexImpl getInstanceOrInvalidate() {
|
||||
if (ourForcedClean.compareAndSet(null, Boolean.TRUE)) {
|
||||
|
||||
@@ -28,7 +28,7 @@ public class AsyncProcessIcon extends AnimatedIcon {
|
||||
public static final int COUNT = 12;
|
||||
public static final int CYCLE_LENGTH = 800;
|
||||
|
||||
public static final Icon[] SMALL_ICONS = findIcons("/process/step_", "/process/step_mask.png");
|
||||
private static final Icon[] SMALL_ICONS = findIcons("/process/step_", "/process/step_mask.png");
|
||||
private boolean myUseMask;
|
||||
|
||||
public AsyncProcessIcon(@NonNls String name) {
|
||||
|
||||
+3
-4
@@ -28,9 +28,8 @@ import java.util.Set;
|
||||
@SuppressWarnings({"NonPrivateFieldAccessedInSynchronizedContext"})
|
||||
@State(
|
||||
name = "FeatureUsageStatistics",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages = {@Storage(
|
||||
file = StoragePathMacros.APP_CONFIG + "/feature.usage.statistics.xml")})
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/feature.usage.statistics.xml", roamingType = RoamingType.DISABLED)}
|
||||
)
|
||||
public class FeatureUsageTrackerImpl extends FeatureUsageTracker implements PersistentStateComponent<Element> {
|
||||
private static final int HOUR = 1000 * 60 * 60;
|
||||
private static final long DAY = HOUR * 24;
|
||||
@@ -92,7 +91,7 @@ public class FeatureUsageTrackerImpl extends FeatureUsageTracker implements Pers
|
||||
if (descriptor != null && System.currentTimeMillis() - descriptor.getLastTimeUsed() > 10 * DAY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return isToBeShown(featureId, project, HOUR);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,10 +34,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
*/
|
||||
@State(
|
||||
name = "RecentDirectoryProjectsManager",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages = {
|
||||
@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml")
|
||||
}
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", roamingType = RoamingType.DISABLED)}
|
||||
)
|
||||
public class RecentDirectoryProjectsManager extends RecentProjectsManagerBase {
|
||||
public RecentDirectoryProjectsManager(MessageBus messageBus) {
|
||||
|
||||
+13
-1
@@ -181,10 +181,22 @@ public class CustomizeIDEWizardDialog extends DialogWrapper implements ActionLis
|
||||
return null;//Prevent closing by <Esc>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCancelAction() {
|
||||
doOKAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
for (AbstractCustomizeWizardStep step : mySteps) {
|
||||
if (!step.beforeOkAction()) return;
|
||||
if (!step.beforeOkAction()) {
|
||||
int index = mySteps.indexOf(step);
|
||||
if (myIndex != index) {
|
||||
myIndex = index;
|
||||
initCurrentStep(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.doOKAction();
|
||||
}
|
||||
|
||||
@@ -87,9 +87,8 @@ import java.util.List;
|
||||
*/
|
||||
@State(
|
||||
name = "LafManager",
|
||||
roamingType = RoamingType.PER_PLATFORM,
|
||||
storages = {@Storage(
|
||||
file = StoragePathMacros.APP_CONFIG + "/options.xml")})
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/options.xml", roamingType = RoamingType.PER_PLATFORM)}
|
||||
)
|
||||
public final class LafManagerImpl extends LafManager implements ApplicationComponent, PersistentStateComponent<Element> {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.ui.LafManager");
|
||||
|
||||
|
||||
+3
-5
@@ -15,15 +15,13 @@
|
||||
*/
|
||||
package com.intellij.ide.util;
|
||||
|
||||
import com.intellij.openapi.components.RoamingType;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.components.StoragePathMacros;
|
||||
|
||||
@State(
|
||||
name = "PropertiesComponent",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages = {@Storage(
|
||||
file = StoragePathMacros.WORKSPACE_FILE)})
|
||||
name = "PropertiesComponent",
|
||||
storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)}
|
||||
)
|
||||
public class ProjectPropertiesComponentImpl extends PropertiesComponentImpl {
|
||||
}
|
||||
|
||||
@@ -34,7 +34,10 @@ import java.util.Set;
|
||||
/**
|
||||
* User: ksafonov
|
||||
*/
|
||||
@State(name = "UsageTrigger", roamingType = RoamingType.DISABLED, storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/statistics.application.usages.xml")})
|
||||
@State(
|
||||
name = "UsageTrigger",
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/statistics.application.usages.xml", roamingType = RoamingType.DISABLED)}
|
||||
)
|
||||
public class UsageTrigger implements PersistentStateComponent<UsageTrigger.State> {
|
||||
|
||||
public static class State {
|
||||
@@ -72,7 +75,7 @@ public class UsageTrigger implements PersistentStateComponent<UsageTrigger.State
|
||||
myState = state;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class MyCollector extends UsagesCollector {
|
||||
|
||||
private static final GroupDescriptor GROUP = GroupDescriptor.create("features counts", GroupDescriptor.HIGHER_PRIORITY);
|
||||
@@ -92,5 +95,5 @@ public class UsageTrigger implements PersistentStateComponent<UsageTrigger.State
|
||||
return GROUP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+1
-5
@@ -43,11 +43,7 @@ import java.util.Set;
|
||||
|
||||
@State(
|
||||
name = "StatisticsApplicationUsages",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages = {
|
||||
@Storage(
|
||||
file = StoragePathMacros.APP_CONFIG + "/statistics.application.usages.xml"
|
||||
)}
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/statistics.application.usages.xml", roamingType = RoamingType.DISABLED)}
|
||||
)
|
||||
public class ApplicationStatisticsPersistenceComponent extends ApplicationStatisticsPersistence
|
||||
implements ApplicationComponent, PersistentStateComponent<Element> {
|
||||
|
||||
+1
-5
@@ -35,11 +35,7 @@ import java.util.Set;
|
||||
|
||||
@State(
|
||||
name = "UsagesStatistic",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages = {
|
||||
@Storage(
|
||||
file = StoragePathMacros.APP_CONFIG + "/usage.statistics.xml"
|
||||
)}
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/usage.statistics.xml", roamingType = RoamingType.DISABLED)}
|
||||
)
|
||||
public class UsageStatisticsPersistenceComponent extends BasicSentUsagesPersistenceComponent
|
||||
implements NamedComponent, PersistentStateComponent<Element> {
|
||||
|
||||
+1
-5
@@ -31,11 +31,7 @@ import java.util.*;
|
||||
*/
|
||||
@State(
|
||||
name = "AbbreviationManager",
|
||||
roamingType = RoamingType.PER_PLATFORM,
|
||||
storages = {
|
||||
@Storage(
|
||||
file = StoragePathMacros.APP_CONFIG + "/abbreviations.xml"
|
||||
)}
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/abbreviations.xml", roamingType = RoamingType.PER_PLATFORM)}
|
||||
)
|
||||
public class AbbreviationManagerImpl extends AbbreviationManager implements
|
||||
ExportableComponent, PersistentStateComponent<Element> {
|
||||
|
||||
+2
-2
@@ -531,10 +531,10 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
@Override
|
||||
public void load(@Nullable String optionsPath) throws IOException {
|
||||
load(PathManager.getConfigPath(), optionsPath);
|
||||
load(PathManager.getConfigPath(), optionsPath == null ? PathManager.getOptionsPath() : optionsPath);
|
||||
}
|
||||
|
||||
public void load(@NotNull String configPath, @Nullable String optionsPath) throws IOException {
|
||||
public void load(@NotNull String configPath, @NotNull String optionsPath) throws IOException {
|
||||
getStateStore().setOptionsPath(optionsPath);
|
||||
getStateStore().setConfigPath(configPath);
|
||||
|
||||
|
||||
+3
-3
@@ -92,13 +92,13 @@ class ApplicationStoreImpl extends ComponentStoreImpl implements IApplicationSto
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptionsPath(final String path) {
|
||||
myStateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.APP_CONFIG), path);
|
||||
public void setOptionsPath(@NotNull String path) {
|
||||
myStateStorageManager.addMacro(StoragePathMacros.APP_CONFIG, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfigPath(@NotNull final String configPath) {
|
||||
myStateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.ROOT_CONFIG), configPath);
|
||||
myStateStorageManager.addMacro(StoragePathMacros.ROOT_CONFIG, configPath);
|
||||
myConfigPath = configPath;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -117,7 +117,7 @@ abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl {
|
||||
}
|
||||
|
||||
public BaseStorageData getMainStorageData() throws StateStorageException {
|
||||
return (BaseStorageData) getMainStorage().getStorageData();
|
||||
return (BaseStorageData)getMainStorage().getStorageData();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
+11
-5
@@ -39,10 +39,10 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
|
||||
private final ProjectManagerImpl myProjectManager;
|
||||
@NonNls private static final String ROOT_TAG_NAME = "defaultProject";
|
||||
|
||||
public DefaultProjectStoreImpl(final ProjectImpl project, final ProjectManagerImpl projectManager) {
|
||||
public DefaultProjectStoreImpl(@NotNull ProjectImpl project, final ProjectManagerImpl projectManager) {
|
||||
super(project);
|
||||
myProjectManager = projectManager;
|
||||
|
||||
myProjectManager = projectManager;
|
||||
myElement = projectManager.getDefaultProjectRootElement();
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
|
||||
return element != null ? element.clone() : null;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected StateStorageManager createStateStorageManager() {
|
||||
@@ -69,7 +68,7 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
|
||||
final Element element = _d;
|
||||
|
||||
final XmlElementStorage storage = new XmlElementStorage(pathMacroManager.createTrackingSubstitutor(), componentManager,
|
||||
ROOT_TAG_NAME, null, "", ComponentRoamingManager.getInstance(),
|
||||
ROOT_TAG_NAME, null, "",
|
||||
ComponentVersionProvider.EMPTY) {
|
||||
@Override
|
||||
@Nullable
|
||||
@@ -115,7 +114,7 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
|
||||
|
||||
return new StateStorageManager() {
|
||||
@Override
|
||||
public void addMacro(String macro, String expansion) {
|
||||
public void addMacro(@NotNull String macro, @NotNull String expansion) {
|
||||
throw new UnsupportedOperationException("Method addMacro not implemented in " + getClass());
|
||||
}
|
||||
|
||||
@@ -131,6 +130,12 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
|
||||
return storage;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType) {
|
||||
return storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public StateStorage getFileStateStorage(@NotNull String fileSpec) {
|
||||
@@ -158,6 +163,7 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
|
||||
storage.finishSave(((MySaveSession)saveSession).saveSession);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String expandMacros(@NotNull String file) {
|
||||
throw new UnsupportedOperationException("Method expandMacros not implemented in " + getClass());
|
||||
|
||||
+2
-2
@@ -65,12 +65,12 @@ class DefaultsStateStorage implements StateStorage {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T getState(final Object component, final String componentName, final Class<T> stateClass, @Nullable final T mergeInto) throws
|
||||
public <T> T getState(final Object component, @NotNull final String componentName, final Class<T> stateClass, @Nullable final T mergeInto) throws
|
||||
StateStorageException {
|
||||
return DefaultStateSerializer.deserializeState(getState(component, componentName), stateClass, mergeInto);
|
||||
}
|
||||
|
||||
public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
|
||||
public boolean hasState(final Object component, @NotNull final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
|
||||
final URL url = DecodeDefaultsUtil.getDefaults(component, componentName);
|
||||
return url != null;
|
||||
}
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T getState(final Object component, final String componentName, Class<T> stateClass, @Nullable T mergeInto)
|
||||
public <T> T getState(final Object component, @NotNull final String componentName, Class<T> stateClass, @Nullable T mergeInto)
|
||||
throws StateStorageException {
|
||||
if (myStorageData == null) myStorageData = loadState();
|
||||
|
||||
|
||||
+20
-14
@@ -22,10 +22,7 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.components.StateStorageException;
|
||||
import com.intellij.openapi.components.StoragePathMacros;
|
||||
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
|
||||
@@ -56,26 +53,29 @@ public class FileBasedStorage extends XmlElementStorage {
|
||||
|
||||
private final String myFilePath;
|
||||
private final File myFile;
|
||||
private final String myRootElementName;
|
||||
private volatile VirtualFile myCachedVirtualFile;
|
||||
|
||||
public FileBasedStorage(@Nullable TrackingPathMacroSubstitutor pathMacroManager,
|
||||
StreamProvider streamProvider,
|
||||
String filePath,
|
||||
String fileSpec,
|
||||
String rootElementName,
|
||||
@Nullable
|
||||
private final RoamingType myRoamingType;
|
||||
|
||||
public FileBasedStorage(@NotNull String filePath,
|
||||
@NotNull String fileSpec,
|
||||
@Nullable RoamingType roamingType,
|
||||
@Nullable TrackingPathMacroSubstitutor pathMacroManager,
|
||||
@NotNull String rootElementName,
|
||||
@NotNull Disposable parentDisposable,
|
||||
PicoContainer picoContainer,
|
||||
ComponentRoamingManager componentRoamingManager,
|
||||
@Nullable StreamProvider streamProvider,
|
||||
ComponentVersionProvider componentVersionProvider) {
|
||||
super(pathMacroManager, parentDisposable, rootElementName, streamProvider, fileSpec, componentRoamingManager, componentVersionProvider);
|
||||
super(pathMacroManager, parentDisposable, rootElementName, streamProvider, fileSpec, componentVersionProvider);
|
||||
|
||||
refreshConfigDirectoryOnce();
|
||||
|
||||
myRootElementName = rootElementName;
|
||||
myFilePath = filePath;
|
||||
myFile = new File(filePath);
|
||||
|
||||
myRoamingType = roamingType;
|
||||
|
||||
VirtualFileTracker virtualFileTracker = ServiceManager.getService(VirtualFileTracker.class);
|
||||
MessageBus messageBus = (MessageBus)picoContainer.getComponentInstanceOfType(MessageBus.class);
|
||||
if (virtualFileTracker != null && messageBus != null) {
|
||||
@@ -101,6 +101,12 @@ public class FileBasedStorage extends XmlElementStorage {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected RoamingType getRoamingType() {
|
||||
return myRoamingType;
|
||||
}
|
||||
|
||||
private static void refreshConfigDirectoryOnce() {
|
||||
Application app = ApplicationManager.getApplication();
|
||||
if (!ourConfigDirectoryRefreshed && (app.isUnitTestMode() || app.isDispatchThread())) {
|
||||
@@ -317,7 +323,7 @@ public class FileBasedStorage extends XmlElementStorage {
|
||||
|
||||
@Nullable
|
||||
public File updateFileExternallyFromStreamProviders() throws IOException {
|
||||
Element element = getElement(loadData(true, null));
|
||||
Element element = getElement(loadData(true, getRoamingType()));
|
||||
if (element == null) {
|
||||
FileUtil.delete(myFile);
|
||||
return null;
|
||||
|
||||
+5
-5
@@ -15,18 +15,18 @@
|
||||
*/
|
||||
package com.intellij.openapi.components.impl.stores;
|
||||
|
||||
import com.intellij.openapi.components.StateStorageException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.components.StateStorage;
|
||||
import com.intellij.openapi.components.StateStorageException;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.Collection;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
public interface IApplicationStore extends IComponentStore {
|
||||
void setOptionsPath(String path);
|
||||
void setOptionsPath(@NotNull String path);
|
||||
|
||||
void setConfigPath(@NotNull String configPath);
|
||||
|
||||
|
||||
+4
-9
@@ -56,17 +56,12 @@ class ProjectStateStorageManager extends StateStorageManagerImpl {
|
||||
assert config != null : "Couldn't find old storage for " + component.getClass().getName();
|
||||
|
||||
final boolean workspace = isWorkspace(config.options);
|
||||
String macro = StoragePathMacros.getMacroName(workspace ? StoragePathMacros.WORKSPACE_FILE : StoragePathMacros.PROJECT_FILE);
|
||||
|
||||
String name = "$" + macro + "$";
|
||||
|
||||
StateStorage storage = getFileStateStorage(name);
|
||||
|
||||
String fileSpec = workspace ? StoragePathMacros.WORKSPACE_FILE : StoragePathMacros.PROJECT_FILE;
|
||||
StateStorage storage = getStateStorage(fileSpec, workspace ? RoamingType.DISABLED : RoamingType.PER_USER);
|
||||
if (operation == StateStorageOperation.READ && storage != null && workspace && !storage.hasState(component, componentName, Element.class, false)) {
|
||||
name = StoragePathMacros.PROJECT_FILE;
|
||||
fileSpec = StoragePathMacros.PROJECT_FILE;
|
||||
}
|
||||
|
||||
return name;
|
||||
return fileSpec;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+44
-42
@@ -54,13 +54,11 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProjectStore {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.ProjectStoreImpl");
|
||||
private static final Logger LOG = Logger.getInstance(ProjectStoreImpl.class);
|
||||
|
||||
@NonNls private static final String OLD_PROJECT_SUFFIX = "_old.";
|
||||
@NonNls static final String OPTION_WORKSPACE = "workspace";
|
||||
|
||||
@NonNls static final String DEFAULT_STATE_STORAGE = StoragePathMacros.PROJECT_FILE;
|
||||
|
||||
static final Storage DEFAULT_STORAGE_ANNOTATION = new MyStorage();
|
||||
private static int originalVersion = -1;
|
||||
|
||||
@@ -68,8 +66,9 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
|
||||
private StorageScheme myScheme = StorageScheme.DEFAULT;
|
||||
private String myPresentableUrl;
|
||||
|
||||
ProjectStoreImpl(final ProjectImpl project) {
|
||||
ProjectStoreImpl(@NotNull ProjectImpl project) {
|
||||
super(project);
|
||||
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@@ -167,15 +166,15 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
|
||||
|
||||
final File dirStore = file.isDirectory() ? new File(file, Project.DIRECTORY_STORE_FOLDER)
|
||||
: new File(file.getParentFile(), Project.DIRECTORY_STORE_FOLDER);
|
||||
stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.PROJECT_FILE), new File(dirStore, "misc.xml").getPath());
|
||||
stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, new File(dirStore, "misc.xml").getPath());
|
||||
|
||||
final File ws = new File(dirStore, "workspace.xml");
|
||||
stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.WORKSPACE_FILE), ws.getPath());
|
||||
stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, ws.getPath());
|
||||
if (!ws.exists() && !file.isDirectory()) {
|
||||
useOldWsContent(filePath, ws);
|
||||
}
|
||||
|
||||
stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.PROJECT_CONFIG_DIR), dirStore.getPath());
|
||||
stateStorageManager.addMacro(StoragePathMacros.PROJECT_CONFIG_DIR, dirStore.getPath());
|
||||
|
||||
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
@@ -187,10 +186,10 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
|
||||
else {
|
||||
myScheme = StorageScheme.DEFAULT;
|
||||
|
||||
stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.PROJECT_FILE), filePath);
|
||||
stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, filePath);
|
||||
|
||||
final String workspacePath = composeWsPath(filePath);
|
||||
stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.WORKSPACE_FILE), workspacePath);
|
||||
stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, workspacePath);
|
||||
|
||||
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
@@ -255,18 +254,27 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
|
||||
|
||||
final String path = getProjectFilePath();
|
||||
if (!StringUtil.isEmptyOrSpaces(path)) {
|
||||
return myScheme == StorageScheme.DEFAULT ? new File(path).getParent() : new File(path).getParentFile().getParent();
|
||||
return getBasePath(new File(path));
|
||||
}
|
||||
|
||||
//we are not yet initialized completely ("open directory", etc)
|
||||
final StateStorage s = getStateStorageManager().getFileStateStorage(StoragePathMacros.PROJECT_FILE);
|
||||
if (!(s instanceof FileBasedStorage)) return null;
|
||||
final FileBasedStorage storage = (FileBasedStorage)s;
|
||||
StateStorage storage = getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER);
|
||||
if (!(storage instanceof FileBasedStorage)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final File file = storage.getFile();
|
||||
if (file == null) return null;
|
||||
File file = ((FileBasedStorage)storage).getFile();
|
||||
return file == null ? null : getBasePath(file);
|
||||
}
|
||||
|
||||
return myScheme == StorageScheme.DEFAULT ? file.getParent() : file.getParentFile().getParent();
|
||||
private String getBasePath(@NotNull File file) {
|
||||
if (myScheme == StorageScheme.DEFAULT) {
|
||||
return file.getParent();
|
||||
}
|
||||
else {
|
||||
File parentFile = file.getParentFile();
|
||||
return parentFile == null ? null : parentFile.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -299,7 +307,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
|
||||
return baseDir.getName().replace(":", "");
|
||||
}
|
||||
else {
|
||||
String temp = getProjectFileName();
|
||||
String temp = ((FileBasedStorage)getProjectFileStorage()).getFile().getName();
|
||||
FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(temp);
|
||||
if (fileType instanceof ProjectFileType) {
|
||||
temp = temp.substring(0, temp.length() - fileType.getDefaultExtension().length() - 1);
|
||||
@@ -312,13 +320,6 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getProjectFileName() {
|
||||
final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(StoragePathMacros.PROJECT_FILE);
|
||||
assert storage != null;
|
||||
return storage.getFileName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public StorageScheme getStorageScheme() {
|
||||
@@ -346,26 +347,28 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
|
||||
|
||||
@Override
|
||||
public VirtualFile getProjectFile() {
|
||||
if (myProject.isDefault()) return null;
|
||||
final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(StoragePathMacros.PROJECT_FILE);
|
||||
return myProject.isDefault() ? null : ((FileBasedStorage)getProjectFileStorage()).getVirtualFile();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private XmlElementStorage getProjectFileStorage() {
|
||||
// XmlElementStorage if default project, otherwise FileBasedStorage
|
||||
XmlElementStorage storage = (XmlElementStorage)getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER);
|
||||
assert storage != null;
|
||||
return storage.getVirtualFile();
|
||||
return storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFile getWorkspaceFile() {
|
||||
if (myProject.isDefault()) return null;
|
||||
final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(StoragePathMacros.WORKSPACE_FILE);
|
||||
final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED);
|
||||
assert storage != null;
|
||||
return storage.getVirtualFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadProjectFromTemplate(@NotNull final ProjectImpl defaultProject) {
|
||||
final StateStorage stateStorage = getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE);
|
||||
|
||||
assert stateStorage instanceof XmlElementStorage;
|
||||
XmlElementStorage xmlElementStorage = (XmlElementStorage)stateStorage;
|
||||
XmlElementStorage stateStorage = getProjectFileStorage();
|
||||
|
||||
defaultProject.save();
|
||||
final IProjectStore projectStore = defaultProject.getStateStore();
|
||||
@@ -373,24 +376,19 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
|
||||
DefaultProjectStoreImpl defaultProjectStore = (DefaultProjectStoreImpl)projectStore;
|
||||
final Element element = defaultProjectStore.getStateCopy();
|
||||
if (element != null) {
|
||||
xmlElementStorage.setDefaultState(element);
|
||||
stateStorage.setDefaultState(element);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getProjectFilePath() {
|
||||
if (myProject.isDefault()) return "";
|
||||
final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(StoragePathMacros.PROJECT_FILE);
|
||||
assert storage != null;
|
||||
return storage.getFilePath();
|
||||
return myProject.isDefault() ? "" : ((FileBasedStorage)getProjectFileStorage()).getFilePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected XmlElementStorage getMainStorage() {
|
||||
final XmlElementStorage storage = (XmlElementStorage)getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE);
|
||||
assert storage != null;
|
||||
return storage;
|
||||
return getProjectFileStorage();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -399,7 +397,6 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
|
||||
return new ProjectStateStorageManager(PathMacroManager.getInstance(getComponentManager()).createTrackingSubstitutor(), myProject);
|
||||
}
|
||||
|
||||
|
||||
static class ProjectStorageData extends BaseStorageData {
|
||||
protected final Project myProject;
|
||||
|
||||
@@ -662,7 +659,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
|
||||
|
||||
@Override
|
||||
public String file() {
|
||||
return DEFAULT_STATE_STORAGE;
|
||||
return StoragePathMacros.PROJECT_FILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -670,6 +667,11 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
|
||||
return StorageScheme.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoamingType roamingType() {
|
||||
return RoamingType.PER_USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends StateStorage> storageClass() {
|
||||
return StateStorage.class;
|
||||
|
||||
+9
-2
@@ -31,7 +31,7 @@ import java.util.Set;
|
||||
* @author mike
|
||||
*/
|
||||
public interface StateStorageManager {
|
||||
void addMacro(String macro, String expansion);
|
||||
void addMacro(@NotNull String macro, @NotNull String expansion);
|
||||
|
||||
@Nullable
|
||||
TrackingPathMacroSubstitutor getMacroSubstitutor();
|
||||
@@ -40,6 +40,13 @@ public interface StateStorageManager {
|
||||
StateStorage getStateStorage(@NotNull Storage storageSpec) throws StateStorageException;
|
||||
|
||||
@Nullable
|
||||
StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType);
|
||||
|
||||
@Deprecated
|
||||
@Nullable
|
||||
/**
|
||||
* @deprecated Use {@link #getStateStorage(String, com.intellij.openapi.components.RoamingType)}
|
||||
*/
|
||||
StateStorage getFileStateStorage(@NotNull String fileSpec);
|
||||
|
||||
@NotNull
|
||||
@@ -58,7 +65,7 @@ public interface StateStorageManager {
|
||||
@Nullable
|
||||
StateStorage getOldStorage(Object component, String componentName, StateStorageOperation operation) throws StateStorageException;
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
String expandMacros(@NotNull String file);
|
||||
|
||||
@Deprecated
|
||||
|
||||
+53
-49
@@ -24,11 +24,13 @@ import com.intellij.openapi.options.CurrentUserHolder;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.RoamingTypeDisabled;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.PathUtilRt;
|
||||
import com.intellij.util.ReflectionUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
@@ -99,9 +101,14 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addMacro(String macro, String expansion) {
|
||||
// avoid hundreds of $MODULE_FILE$ instances
|
||||
myMacros.put(("$" + macro + "$").intern(), expansion);
|
||||
public synchronized void addMacro(@NotNull String macro, @NotNull String expansion) {
|
||||
assert !macro.isEmpty();
|
||||
// backward compatibility
|
||||
if (macro.charAt(0) != '$') {
|
||||
LOG.warn("Add macros instead of macro name: " + macro);
|
||||
expansion = '$' + macro + '$';
|
||||
}
|
||||
myMacros.put(macro, expansion);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,15 +130,15 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public StateStorage getFileStateStorage(@NotNull String fileName) {
|
||||
@Override
|
||||
public StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType) {
|
||||
myStorageLock.lock();
|
||||
try {
|
||||
StateStorage stateStorage = myStorages.get(fileName);
|
||||
StateStorage stateStorage = myStorages.get(fileSpec);
|
||||
if (stateStorage == null) {
|
||||
stateStorage = createFileStateStorage(fileName);
|
||||
putStorageToMap(fileName, stateStorage);
|
||||
stateStorage = createFileStateStorage(fileSpec, roamingType);
|
||||
putStorageToMap(fileSpec, stateStorage);
|
||||
}
|
||||
return stateStorage;
|
||||
}
|
||||
@@ -140,6 +147,12 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public StateStorage getFileStateStorage(@NotNull String fileSpec) {
|
||||
return getStateStorage(fileSpec, RoamingType.PER_USER);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<String> getStorageFileNames() {
|
||||
@@ -185,7 +198,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
|
||||
if (!storageSpec.stateSplitter().equals(StateSplitter.class)) {
|
||||
return createDirectoryStateStorage(storageSpec.file(), storageSpec.stateSplitter());
|
||||
}
|
||||
return createFileStateStorage(storageSpec.file());
|
||||
return createFileStateStorage(storageSpec.file(), storageSpec.roamingType());
|
||||
}
|
||||
|
||||
private static String getStorageSpecId(Storage storageSpec) {
|
||||
@@ -210,40 +223,30 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
|
||||
|
||||
@Nullable
|
||||
private StateStorage createDirectoryStateStorage(String file, Class<? extends StateSplitter> splitterClass) throws StateStorageException {
|
||||
String expandedFile = expandMacros(file);
|
||||
if (expandedFile == null) {
|
||||
myStorages.put(file, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
final StateSplitter splitter;
|
||||
try {
|
||||
splitter = splitterClass.newInstance();
|
||||
splitter = ReflectionUtil.newInstance(splitterClass);
|
||||
}
|
||||
catch (InstantiationException e) {
|
||||
catch (RuntimeException e) {
|
||||
throw new StateStorageException(e);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
throw new StateStorageException(e);
|
||||
}
|
||||
|
||||
return new DirectoryBasedStorage(myPathMacroSubstitutor, expandedFile, splitter, this, myPicoContainer);
|
||||
return new DirectoryBasedStorage(myPathMacroSubstitutor, expandMacros(file), splitter, this, myPicoContainer);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private StateStorage createFileStateStorage(@NotNull final String fileSpec) {
|
||||
private StateStorage createFileStateStorage(@NotNull final String fileSpec, @Nullable RoamingType roamingType) {
|
||||
String expandedFile = expandMacros(fileSpec);
|
||||
if (expandedFile == null) {
|
||||
myStorages.put(fileSpec, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!ourHeadlessEnvironment && PathUtilRt.getFileName(expandedFile).lastIndexOf('.') < 0) {
|
||||
throw new IllegalArgumentException("Extension is missing for storage file: " + expandedFile);
|
||||
}
|
||||
|
||||
return new FileBasedStorage(getMacroSubstitutor(fileSpec), getStreamProvider(), expandedFile, fileSpec, myRootTagName, this,
|
||||
myPicoContainer, ComponentRoamingManager.getInstance(), this) {
|
||||
if (fileSpec.equals(StoragePathMacros.WORKSPACE_FILE)) {
|
||||
roamingType = RoamingType.DISABLED;
|
||||
}
|
||||
|
||||
return new FileBasedStorage(expandedFile, fileSpec, roamingType, getMacroSubstitutor(fileSpec), myRootTagName, this,
|
||||
myPicoContainer, getStreamProvider(), this) {
|
||||
@Override
|
||||
@NotNull
|
||||
protected StorageData createStorageData() {
|
||||
@@ -271,8 +274,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
|
||||
String filePath = getNotNullVersionsFilePath();
|
||||
if (filePath != null) {
|
||||
try {
|
||||
Document document = JDOMUtil.loadDocument(new File(filePath));
|
||||
loadComponentVersions(result, document);
|
||||
loadComponentVersions(result, JDOMUtil.loadDocument(new File(filePath)));
|
||||
}
|
||||
catch (JDOMException e) {
|
||||
LOG.debug(e);
|
||||
@@ -294,6 +296,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
|
||||
|
||||
public static void loadComponentVersions(TObjectLongHashMap<String> result, Document document) {
|
||||
List<Element> componentObjects = document.getRootElement().getChildren("component");
|
||||
result.ensureCapacity(componentObjects.size());
|
||||
for (Element component : componentObjects) {
|
||||
String name = component.getAttributeValue("name");
|
||||
String version = component.getAttributeValue("version");
|
||||
@@ -330,26 +333,22 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
|
||||
private static final Pattern MACRO_PATTERN = Pattern.compile("(\\$[^\\$]*\\$)");
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
@NotNull
|
||||
public synchronized String expandMacros(@NotNull String file) {
|
||||
final Matcher matcher = MACRO_PATTERN.matcher(file);
|
||||
String expanded = file;
|
||||
for (String macro : myMacros.keySet()) {
|
||||
expanded = StringUtil.replace(expanded, macro, myMacros.get(macro));
|
||||
}
|
||||
|
||||
final Matcher matcher = MACRO_PATTERN.matcher(expanded);
|
||||
while (matcher.find()) {
|
||||
String m = matcher.group(1);
|
||||
if (!myMacros.containsKey(m) || !ApplicationManager.getApplication().isUnitTestMode() && myMacros.get(m) == null) {
|
||||
throw new IllegalArgumentException("Unknown macro: " + m + " in storage spec: " + file);
|
||||
if (!myMacros.containsKey(m)) {
|
||||
throw new IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file);
|
||||
}
|
||||
}
|
||||
|
||||
String actualFile = file;
|
||||
|
||||
for (String macro : myMacros.keySet()) {
|
||||
final String replacement = myMacros.get(macro);
|
||||
if (replacement != null) {
|
||||
actualFile = StringUtil.replace(actualFile, macro, replacement);
|
||||
}
|
||||
}
|
||||
|
||||
return actualFile;
|
||||
return expanded;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -425,7 +424,8 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
|
||||
@Nullable
|
||||
public StateStorage getOldStorage(Object component, String componentName, StateStorageOperation operation) throws StateStorageException {
|
||||
String oldStorageSpec = getOldStorageSpec(component, componentName, operation);
|
||||
return oldStorageSpec == null ? null : getFileStateStorage(oldStorageSpec);
|
||||
//noinspection deprecation
|
||||
return oldStorageSpec == null ? null : getStateStorage(oldStorageSpec, component instanceof RoamingTypeDisabled ? RoamingType.DISABLED : RoamingType.PER_USER);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -504,12 +504,16 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
|
||||
}
|
||||
|
||||
public void save() {
|
||||
if (!isDirty) return;
|
||||
if (!isDirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
String filePath = getNotNullVersionsFilePath();
|
||||
if (filePath != null) {
|
||||
FileUtilRt.createParentDirs(new File(filePath));
|
||||
File file = new File(filePath);
|
||||
FileUtilRt.createParentDirs(file);
|
||||
try {
|
||||
JDOMUtil.writeDocument(new Document(createComponentVersionsXml(getComponentVersions())), filePath, "\n");
|
||||
JDOMUtil.writeParent(createComponentVersionsXml(getComponentVersions()), file, "\n");
|
||||
isDirty = false;
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
||||
+2
-2
@@ -291,7 +291,7 @@ public class StorageUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static BufferExposingByteArrayOutputStream documentToBytes(@NotNull Parent element, boolean useSystemLineSeparator) throws IOException {
|
||||
public static BufferExposingByteArrayOutputStream elementToBytes(@NotNull Parent element, boolean useSystemLineSeparator) throws IOException {
|
||||
return writeToBytes(element, useSystemLineSeparator ? SystemProperties.getLineSeparator() : "\n");
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ public class StorageUtil {
|
||||
*/
|
||||
public static void doSendContent(@NotNull StreamProvider provider, @NotNull String fileSpec, @NotNull Parent element, @NotNull RoamingType type, boolean async) throws IOException {
|
||||
// we should use standard line-separator (\n) - stream provider can share file content on any OS
|
||||
BufferExposingByteArrayOutputStream content = documentToBytes(element, false);
|
||||
BufferExposingByteArrayOutputStream content = elementToBytes(element, false);
|
||||
provider.saveContent(fileSpec, content.getInternalBuffer(), content.size(), type, async);
|
||||
}
|
||||
|
||||
|
||||
+28
-8
@@ -48,7 +48,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
|
||||
private static final String VERSION_FILE_SUFFIX = ".ver";
|
||||
|
||||
protected TrackingPathMacroSubstitutor myPathMacroSubstitutor;
|
||||
@NotNull private final String myRootElementName;
|
||||
@NotNull protected final String myRootElementName;
|
||||
private Object mySession;
|
||||
private StorageData myLoadedData;
|
||||
protected final StreamProvider myStreamProvider;
|
||||
@@ -78,13 +78,12 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
|
||||
@NotNull String rootElementName,
|
||||
@Nullable StreamProvider streamProvider,
|
||||
String fileSpec,
|
||||
ComponentRoamingManager componentRoamingManager,
|
||||
ComponentVersionProvider componentVersionProvider) {
|
||||
myPathMacroSubstitutor = pathMacroSubstitutor;
|
||||
myRootElementName = rootElementName;
|
||||
myStreamProvider = streamProvider;
|
||||
myFileSpec = fileSpec;
|
||||
myComponentRoamingManager = componentRoamingManager;
|
||||
myComponentRoamingManager = ComponentRoamingManager.getInstance();
|
||||
Disposer.register(parentDisposable, this);
|
||||
|
||||
myLocalVersionProvider = componentVersionProvider;
|
||||
@@ -95,6 +94,11 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
|
||||
return myDisposed;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected RoamingType getRoamingType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract Element loadLocalData();
|
||||
|
||||
@@ -133,7 +137,8 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
|
||||
return myLoadedData;
|
||||
}
|
||||
|
||||
myLoadedData = loadData(true, myFileSpec.equals(StoragePathMacros.WORKSPACE_FILE) ? null : myComponentRoamingManager.getRoamingType(componentName));
|
||||
RoamingType roamingType = getRoamingType();
|
||||
myLoadedData = loadData(true, roamingType == null ? myComponentRoamingManager.getRoamingType(componentName) : roamingType);
|
||||
return myLoadedData;
|
||||
}
|
||||
|
||||
@@ -423,17 +428,32 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
|
||||
}
|
||||
|
||||
private void saveForProvider(@NotNull StreamProvider streamProvider) {
|
||||
if (!streamProvider.isApplicable(myFileSpec, RoamingType.PER_USER)) {
|
||||
RoamingType roamingType = getRoamingType();
|
||||
if (roamingType != null && roamingType == RoamingType.DISABLED) {
|
||||
// todo our old stream provider doesn't share WORKSPACE_FILE, but our new has this feature - are we really want to support it?
|
||||
return;
|
||||
}
|
||||
|
||||
if (!streamProvider.isApplicable(myFileSpec, roamingType == null ? RoamingType.PER_USER : roamingType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Element element = getElementToSave();
|
||||
if (element == null || element.getChildren().isEmpty()) {
|
||||
streamProvider.delete(myFileSpec, RoamingType.PER_USER);
|
||||
streamProvider.delete(myFileSpec, RoamingType.PER_PLATFORM);
|
||||
streamProvider.delete(myFileSpec, roamingType == null ? RoamingType.PER_USER : roamingType);
|
||||
if (roamingType == null) {
|
||||
streamProvider.delete(myFileSpec, RoamingType.PER_PLATFORM);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (roamingType != null) {
|
||||
doSaveForProvider(element, roamingType, streamProvider);
|
||||
return;
|
||||
}
|
||||
|
||||
// todo check when roamingType is null and remove next code (we fixed platforms and plugins, but next code should not be removed due to backward compatibility)
|
||||
|
||||
// skip the whole document if some component has disabled roaming type
|
||||
// you must not store components with different roaming types in one document
|
||||
// one exclusion: workspace file (you don't have choice in this case)
|
||||
@@ -554,7 +574,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
|
||||
|
||||
@Override
|
||||
public void reload(@NotNull final Set<String> changedComponents) throws StateStorageException {
|
||||
final StorageData storageData = loadData(false, null);
|
||||
final StorageData storageData = loadData(false, getRoamingType());
|
||||
final StorageData oldLoadedData = myLoadedData;
|
||||
if (oldLoadedData != null) {
|
||||
Set<String> componentsToRetain = new THashSet<String>(oldLoadedData.myComponentStates.keySet());
|
||||
|
||||
+3
-1
@@ -1158,7 +1158,9 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
|
||||
}
|
||||
|
||||
public Editor getSelectedTextEditor(boolean lockfree) {
|
||||
assertDispatchThread();
|
||||
if (!lockfree) {
|
||||
assertDispatchThread();
|
||||
}
|
||||
|
||||
final EditorWindow currentWindow = lockfree ? getMainSplitters().getCurrentWindow() : getSplitters().getCurrentWindow();
|
||||
if (currentWindow != null) {
|
||||
|
||||
@@ -33,7 +33,6 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jdom.Document;
|
||||
import org.jdom.Element;
|
||||
import org.jdom.JDOMException;
|
||||
import org.jdom.Parent;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -45,11 +44,7 @@ import java.util.*;
|
||||
|
||||
@State(
|
||||
name = "KeymapManager",
|
||||
roamingType = RoamingType.PER_PLATFORM,
|
||||
storages = {
|
||||
@Storage(
|
||||
file = StoragePathMacros.APP_CONFIG + "/keymap.xml"
|
||||
)}
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/keymap.xml", roamingType = RoamingType.PER_PLATFORM)}
|
||||
)
|
||||
public class KeymapManagerImpl extends KeymapManagerEx implements PersistentStateComponent<Element>, ExportableApplicationComponent {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.keymap.KeymapManager");
|
||||
|
||||
+4
-59
@@ -28,8 +28,6 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class SchemesManagerFactoryImpl extends SchemesManagerFactory implements SettingsSavingComponent {
|
||||
@@ -47,63 +45,10 @@ public class SchemesManagerFactoryImpl extends SchemesManagerFactory implements
|
||||
}
|
||||
IApplicationStore applicationStore = ((ApplicationImpl)application).getStateStore();
|
||||
String baseDirPath = applicationStore.getStateStorageManager().expandMacros(fileSpec);
|
||||
if (baseDirPath != null) {
|
||||
StreamProvider provider = applicationStore.getStateStorageManager().getStreamProvider();
|
||||
SchemesManagerImpl<T, E> manager = new SchemesManagerImpl<T, E>(fileSpec, processor, roamingType, provider, new File(baseDirPath));
|
||||
myRegisteredManagers.add(manager);
|
||||
return manager;
|
||||
}
|
||||
else {
|
||||
return new AbstractSchemesManager<T, E>() {
|
||||
@Override
|
||||
@NotNull
|
||||
public Collection<E> loadSchemes() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Collection<SharedScheme<E>> loadSharedSchemes(final Collection<T> currentSchemeList) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportScheme(@NotNull final E scheme, final String name, final String description) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImportAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShared(final Scheme scheme) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSchemeDeleted(final Scheme toDelete) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSchemeAdded(final T scheme) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExportAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getRootDirectory() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
StreamProvider provider = applicationStore.getStateStorageManager().getStreamProvider();
|
||||
SchemesManagerImpl<T, E> manager = new SchemesManagerImpl<T, E>(fileSpec, processor, roamingType, provider, new File(baseDirPath));
|
||||
myRegisteredManagers.add(manager);
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -80,7 +80,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
|
||||
|
||||
private boolean myListenerAdded = false;
|
||||
private Alarm myRefreshAlarm;
|
||||
|
||||
|
||||
private String mySchemeExtension = DEFAULT_EXT;
|
||||
private boolean myUpgradeExtension = false;
|
||||
|
||||
@@ -536,7 +536,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
|
||||
@Nullable
|
||||
private static Document loadGlobalScheme(final String schemePath) throws IOException {
|
||||
StreamProvider provider = getProvider();
|
||||
return provider != null && provider.isEnabled() ? StorageUtil.loadDocument(provider.loadContent(schemePath, RoamingType.GLOBAL)) : null;
|
||||
return provider != null && provider.isEnabled() ? StorageUtil.loadDocument(provider.loadContent(schemePath, getRoamingType(provider))) : null;
|
||||
}
|
||||
|
||||
private void saveFileName(String fileName, final E schemeKey) {
|
||||
@@ -610,9 +610,9 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
|
||||
|
||||
Collection<String> names = new THashSet<String>(getAllSchemeNames(currentSchemeList));
|
||||
Map<String, SharedScheme<E>> result = new THashMap<String, SharedScheme<E>>();
|
||||
for (String subPath : provider.listSubFiles(myFileSpec, RoamingType.GLOBAL)) {
|
||||
for (String subPath : provider.listSubFiles(myFileSpec, getRoamingType(provider))) {
|
||||
try {
|
||||
final Document subDocument = StorageUtil.loadDocument(provider.loadContent(getFileFullPath(subPath), RoamingType.GLOBAL));
|
||||
final Document subDocument = StorageUtil.loadDocument(provider.loadContent(getFileFullPath(subPath), getRoamingType(provider)));
|
||||
if (subDocument != null) {
|
||||
SharedSchemeData original = unwrap(subDocument);
|
||||
final E scheme = myProcessor.readScheme(original.original);
|
||||
@@ -674,6 +674,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
|
||||
return myFileSpec + '/' + subPath;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void exportScheme(@NotNull final E scheme, final String name, final String description) throws WriteExternalException, IOException {
|
||||
StreamProvider provider = getProvider();
|
||||
@@ -684,7 +685,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
|
||||
Parent document = myProcessor.writeScheme(scheme);
|
||||
if (document != null) {
|
||||
String fileSpec = getFileFullPath(UniqueFileNamesProvider.convertName(scheme.getName())) + mySchemeExtension;
|
||||
if (!provider.isApplicable(fileSpec, RoamingType.GLOBAL)) {
|
||||
if (!provider.isApplicable(fileSpec, getRoamingType(provider))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -696,10 +697,17 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
|
||||
wrapped.setAttribute(USER, userName);
|
||||
}
|
||||
}
|
||||
StorageUtil.doSendContent(provider, fileSpec, wrapped, RoamingType.GLOBAL, false);
|
||||
StorageUtil.doSendContent(provider, fileSpec, wrapped, getRoamingType(provider), false);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@NotNull
|
||||
private static RoamingType getRoamingType(@NotNull StreamProvider provider) {
|
||||
// for deprecated old stream we use GLOBAL as before to preserve backward compatibility
|
||||
return provider instanceof CurrentUserHolder ? RoamingType.GLOBAL : RoamingType.PER_USER;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Element wrap(@NotNull Parent original, @NotNull String name, @NotNull String description) {
|
||||
Element sharedElement = new Element(SHARED_SCHEME_ORIGINAL);
|
||||
@@ -897,7 +905,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
|
||||
|
||||
private void saveIfNeeded(E schemeKey, String fileName, Parent element, long newHash, Long oldHash) throws IOException {
|
||||
if (oldHash == null || newHash != oldHash.longValue() || myVFSBaseDir.findChild(fileName) == null) {
|
||||
ensureFileText(fileName, StorageUtil.documentToBytes(element, true).toByteArray());
|
||||
ensureFileText(fileName, StorageUtil.elementToBytes(element, true).toByteArray());
|
||||
schemeKey.getExternalInfo().setHash(newHash);
|
||||
saveFileName(fileName, schemeKey);
|
||||
saveOnServer(fileName, element);
|
||||
|
||||
@@ -67,7 +67,6 @@ import java.util.Set;
|
||||
*/
|
||||
@State(
|
||||
name = "WindowManager",
|
||||
roamingType = RoamingType.GLOBAL,
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/window.manager.xml")})
|
||||
public final class WindowManagerImpl extends WindowManagerEx implements NamedComponent, PersistentStateComponent<Element> {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.wm.impl.WindowManagerImpl");
|
||||
|
||||
+1
-1
@@ -161,7 +161,7 @@ public class ApplicationStoreTest extends LightPlatformLangTestCase {
|
||||
}
|
||||
};
|
||||
|
||||
stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.APP_CONFIG), testAppConfigPath);
|
||||
stateStorageManager.addMacro(StoragePathMacros.APP_CONFIG, testAppConfigPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+7
-6
@@ -16,6 +16,7 @@
|
||||
package com.intellij.openapi.components.impl;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.RoamingType;
|
||||
import com.intellij.openapi.components.StateStorage;
|
||||
import com.intellij.openapi.components.StateStorageException;
|
||||
import com.intellij.openapi.components.StateStorageOperation;
|
||||
@@ -55,7 +56,7 @@ public class StateStorageManagerImplTest extends LightPlatformLangTestCase {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
myStateStorageManager.addMacro("MACRO1", "/temp/m1");
|
||||
myStateStorageManager.addMacro("$MACRO1$", "/temp/m1");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,23 +66,23 @@ public class StateStorageManagerImplTest extends LightPlatformLangTestCase {
|
||||
}
|
||||
|
||||
public void testCreateFileStateStorageMacroSubstituted() {
|
||||
StateStorage data = myStateStorageManager.getFileStateStorage("$MACRO1$/test.xml");
|
||||
StateStorage data = myStateStorageManager.getStateStorage("$MACRO1$/test.xml", RoamingType.PER_USER);
|
||||
assertThat(data, is(notNullValue()));
|
||||
}
|
||||
|
||||
public void testCreateStateStorageAssertionThrownWhenUnknownMacro() {
|
||||
try {
|
||||
myStateStorageManager.getFileStateStorage("$UNKNOWN_MACRO$/test.xml");
|
||||
myStateStorageManager.getStateStorage("$UNKNOWN_MACRO$/test.xml", RoamingType.PER_USER);
|
||||
fail("Exception expected");
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertEquals("Unknown macro: $UNKNOWN_MACRO$ in storage spec: $UNKNOWN_MACRO$/test.xml", e.getMessage());
|
||||
assertEquals("Unknown macro: $UNKNOWN_MACRO$ in storage file spec: $UNKNOWN_MACRO$/test.xml", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateFileStateStorageMacroSubstitutedWhenExpansionHas$() {
|
||||
myStateStorageManager.addMacro("DOLLAR_MACRO", "/temp/d$");
|
||||
StateStorage data = myStateStorageManager.getFileStateStorage("$DOLLAR_MACRO$/test.xml");
|
||||
myStateStorageManager.addMacro("$DOLLAR_MACRO$", "/temp/d$");
|
||||
StateStorage data = myStateStorageManager.getStateStorage("$DOLLAR_MACRO$/test.xml", RoamingType.PER_USER);
|
||||
assertThat(data, is(notNullValue()));
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -19,7 +19,6 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.components.StateStorage;
|
||||
import com.intellij.openapi.components.StateStorageException;
|
||||
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
|
||||
import com.intellij.openapi.components.impl.stores.ComponentRoamingManager;
|
||||
import com.intellij.openapi.components.impl.stores.ComponentVersionProvider;
|
||||
import com.intellij.openapi.components.impl.stores.XmlElementStorage;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
@@ -88,7 +87,7 @@ public class XmlElementStorageTest extends LightPlatformLangTestCase {
|
||||
private Element mySavedElement;
|
||||
|
||||
public MyXmlElementStorage(Element element, final Disposable parentDisposable) throws StateStorageException {
|
||||
super(new MyPathMacroManager(), parentDisposable, "root", null, "", ComponentRoamingManager.getInstance(), ComponentVersionProvider.EMPTY);
|
||||
super(new MyPathMacroManager(), parentDisposable, "root", null, "", ComponentVersionProvider.EMPTY);
|
||||
myElement = element;
|
||||
}
|
||||
|
||||
@@ -123,7 +122,7 @@ public class XmlElementStorageTest extends LightPlatformLangTestCase {
|
||||
|
||||
private static class MyPathMacroManager implements TrackingPathMacroSubstitutor {
|
||||
@Override
|
||||
public void expandPaths(final Element element) {
|
||||
public void expandPaths(@NotNull final Element element) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,7 +135,7 @@ public class XmlElementStorageTest extends LightPlatformLangTestCase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collapsePaths(final Element element) {
|
||||
public void collapsePaths(@NotNull final Element element) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,10 +23,9 @@ import java.lang.annotation.RetentionPolicy;
|
||||
public @interface State {
|
||||
String name();
|
||||
|
||||
@Deprecated
|
||||
/**
|
||||
* {@link RoamingType#GLOBAL} will be ignored because it doesn't matter - global or per project depends on file spec (used storage macros).
|
||||
*
|
||||
* You must not store components with different roaming types in one file ({@link com.intellij.openapi.components.Storage#file()}).
|
||||
* @deprecated Use {@link Storage#roamingType()}
|
||||
*/
|
||||
RoamingType roamingType() default RoamingType.PER_USER;
|
||||
|
||||
|
||||
@@ -32,9 +32,9 @@ public interface StateStorage {
|
||||
Topic<Listener> STORAGE_TOPIC = new Topic<Listener>("STORAGE_LISTENER", Listener.class, Topic.BroadcastDirection.TO_PARENT);
|
||||
|
||||
@Nullable
|
||||
<T> T getState(final Object component, final String componentName, Class<T> stateClass, @Nullable T mergeInto) throws StateStorageException;
|
||||
<T> T getState(final Object component, @NotNull String componentName, Class<T> stateClass, @Nullable T mergeInto) throws StateStorageException;
|
||||
|
||||
boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException;
|
||||
boolean hasState(final Object component, @NotNull String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException;
|
||||
|
||||
@NotNull
|
||||
ExternalizationSession startExternalization();
|
||||
|
||||
@@ -28,6 +28,11 @@ public @interface Storage {
|
||||
@NonNls String file() default "";
|
||||
StorageScheme scheme() default StorageScheme.DEFAULT;
|
||||
|
||||
/**
|
||||
* You must not store components with different roaming types in one file ({@link #file()}).
|
||||
*/
|
||||
RoamingType roamingType() default RoamingType.PER_USER;
|
||||
|
||||
Class<? extends StateStorage> storageClass() default StateStorage.class;
|
||||
Class<? extends StateSplitter> stateSplitter() default StateSplitter.class;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ public class StoragePathMacros {
|
||||
* @throws IllegalArgumentException if given macro definition has unexpected format
|
||||
*/
|
||||
@NotNull
|
||||
@Deprecated
|
||||
public static String getMacroName(@NotNull String macro) throws IllegalArgumentException {
|
||||
if (macro.length() < 3 || macro.charAt(0) != '$' || macro.charAt(macro.length() - 1) != '$') {
|
||||
throw new IllegalArgumentException("Malformed macro definition (" + macro + ")");
|
||||
|
||||
@@ -35,10 +35,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
@State(
|
||||
name = "PathMacrosImpl",
|
||||
roamingType = RoamingType.PER_PLATFORM,
|
||||
storages = {
|
||||
@Storage(file = StoragePathMacros.APP_CONFIG + "/path.macros.xml")
|
||||
}
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/path.macros.xml", roamingType = RoamingType.PER_PLATFORM)}
|
||||
)
|
||||
public class PathMacrosImpl extends PathMacros implements PersistentStateComponent<Element> {
|
||||
private static final Logger LOG = Logger.getInstance(PathMacrosImpl.class);
|
||||
|
||||
@@ -25,12 +25,6 @@ public abstract class PathMacroManager implements PathMacroSubstitutor {
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void expandPaths(@NotNull Element element);
|
||||
|
||||
@Override
|
||||
public abstract void collapsePaths(@NotNull Element element);
|
||||
|
||||
public abstract void collapsePathsRecursively(@NotNull Element element);
|
||||
|
||||
public abstract String collapsePathsRecursively(@NotNull String text);
|
||||
|
||||
+3
-2
@@ -16,6 +16,7 @@
|
||||
package com.intellij.openapi.components;
|
||||
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface PathMacroSubstitutor {
|
||||
@@ -23,7 +24,7 @@ public interface PathMacroSubstitutor {
|
||||
|
||||
String collapsePath(@Nullable String path);
|
||||
|
||||
void expandPaths(Element element);
|
||||
void expandPaths(@NotNull Element element);
|
||||
|
||||
void collapsePaths(Element element);
|
||||
void collapsePaths(@NotNull Element element);
|
||||
}
|
||||
|
||||
+2
-2
@@ -182,12 +182,12 @@ public class BasePathMacroManager extends PathMacroManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expandPaths(final Element element) {
|
||||
public void expandPaths(@NotNull final Element element) {
|
||||
getExpandMacroMap().substitute(element, SystemInfo.isFileSystemCaseSensitive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collapsePaths(final Element element) {
|
||||
public void collapsePaths(@NotNull final Element element) {
|
||||
getReplacePathMap().substitute(element, SystemInfo.isFileSystemCaseSensitive, false, ourFilter);
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,13 @@ public class RootIndex {
|
||||
private final TObjectIntHashMap<JpsModuleSourceRootType<?>> myRootTypeId = new TObjectIntHashMap<JpsModuleSourceRootType<?>>();
|
||||
@NotNull private final Project myProject;
|
||||
private volatile Map<VirtualFile, OrderEntry[]> myOrderEntries;
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private final LowMemoryWatcher myLowMemoryWatcher = LowMemoryWatcher.register(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myNonExistentPackages.clear();
|
||||
}
|
||||
});
|
||||
|
||||
// made public for Upsource
|
||||
public RootIndex(@NotNull Project project, @NotNull InfoCache cache) {
|
||||
@@ -90,12 +97,6 @@ public class RootIndex {
|
||||
myProjectExcludedRoots.add(root);
|
||||
}
|
||||
}
|
||||
LowMemoryWatcher.register(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myNonExistentPackages.clear();
|
||||
}
|
||||
}, project);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -191,9 +191,6 @@ compiler.process.use.memory.temp.cache=true
|
||||
compiler.process.use.memory.temp.cache.description=Store temporary data in memory for faster compilation;\
|
||||
requires larger heap size for the build process. If parallel build is enabled, the option is ignored and temp data is always stored in memory.
|
||||
|
||||
compiler.process.use.external.javac=false
|
||||
compiler.process.use.external.javac.description=Run javac compiler in a separate process (allows to run build process with smaller heap size).
|
||||
|
||||
compiler.process.debug.port=-1
|
||||
|
||||
compiler.automake.trigger.delay=300
|
||||
|
||||
+6
@@ -30,13 +30,19 @@ public class CommandLineTokenizerTest extends TestCase {
|
||||
|
||||
public void testEscape() throws Exception {
|
||||
assertTokens("a\\ b", true, "a b");
|
||||
assertTokens("a\\ b", false, "a\\", "b");
|
||||
|
||||
assertTokens("\"a\\ b\"", true, "a\\ b");
|
||||
assertTokens("\"a\\ b\"", false, "a\\ b");
|
||||
|
||||
assertTokens("a\\ ", true, "a ");
|
||||
assertTokens("a\\ ", false, "a\\");
|
||||
|
||||
assertTokens("\\\"", "\"");
|
||||
assertTokens("\"\\\" a \\\"\"", "\" a \"");
|
||||
assertTokens("\\\"a b\\\"", "\"a", "b\"");
|
||||
assertTokens("\\\"a\\ b\\\"", true, "\"a b\"");
|
||||
assertTokens("\\\"a\\ b\\\"", false, "\"a\\", "b\"");
|
||||
}
|
||||
|
||||
private static void assertTokens(String cmd, String... tokens) {
|
||||
|
||||
+6
-7
@@ -21,7 +21,10 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.components.StoragePathMacros;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressManagerQueue;
|
||||
@@ -64,12 +67,8 @@ import java.util.concurrent.TimeUnit;
|
||||
* @author yole
|
||||
*/
|
||||
@State(
|
||||
name="CommittedChangesCache",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages= {
|
||||
@Storage(
|
||||
file = StoragePathMacros.WORKSPACE_FILE
|
||||
)}
|
||||
name = "CommittedChangesCache",
|
||||
storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)}
|
||||
)
|
||||
public class CommittedChangesCache implements PersistentStateComponent<CommittedChangesCache.State> {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.committed.CommittedChangesCache");
|
||||
|
||||
+3
-1
@@ -30,6 +30,8 @@ import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.openapi.actionSystem.PlatformDataKeys.CONTEXT_COMPONENT;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
@@ -49,7 +51,7 @@ public class XMarkObjectActionHandler extends MarkObjectActionHandler {
|
||||
markers.unmarkValue(value);
|
||||
}
|
||||
else {
|
||||
ValueMarkerPresentationDialog dialog = new ValueMarkerPresentationDialog(event.getInputEvent().getComponent(), node.getName());
|
||||
ValueMarkerPresentationDialog dialog = new ValueMarkerPresentationDialog(event.getData(CONTEXT_COMPONENT), node.getName());
|
||||
dialog.show();
|
||||
ValueMarkup markup = dialog.getConfiguredMarkup();
|
||||
if (dialog.isOK() && markup != null) {
|
||||
|
||||
@@ -61,6 +61,7 @@ public class XFramesView extends XDebugView {
|
||||
private final ComboBox myThreadComboBox;
|
||||
private final Set<XExecutionStack> myExecutionStacks = ContainerUtil.newHashSet();
|
||||
private XExecutionStack mySelectedStack;
|
||||
private int mySelectedFrameIndex;
|
||||
private boolean myListenersEnabled;
|
||||
private final Map<XExecutionStack, StackFramesListBuilder> myBuilders = new HashMap<XExecutionStack, StackFramesListBuilder>();
|
||||
private final ActionToolbarImpl myToolbar;
|
||||
@@ -76,7 +77,7 @@ public class XFramesView extends XDebugView {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
if (myListenersEnabled && !e.getValueIsAdjusting()) {
|
||||
processFrameSelection(e);
|
||||
processFrameSelection(getSession(e));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -86,7 +87,7 @@ public class XFramesView extends XDebugView {
|
||||
if (myListenersEnabled) {
|
||||
int i = myFramesList.locationToIndex(e.getPoint());
|
||||
if (i != -1 && myFramesList.isSelectedIndex(i)) {
|
||||
processFrameSelection(e);
|
||||
processFrameSelection(getSession(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,9 +116,10 @@ public class XFramesView extends XDebugView {
|
||||
|
||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||
Object item = e.getItem();
|
||||
if (item instanceof XExecutionStack) {
|
||||
if (item != mySelectedStack && item instanceof XExecutionStack) {
|
||||
XDebugSession session = getSession(e);
|
||||
if (session != null) {
|
||||
mySelectedFrameIndex = 0;
|
||||
updateFrames((XExecutionStack)item, session);
|
||||
}
|
||||
}
|
||||
@@ -209,16 +211,21 @@ public class XFramesView extends XDebugView {
|
||||
XStackFrame currentStackFrame = session == null ? null : session.getCurrentStackFrame();
|
||||
if (currentStackFrame != null) {
|
||||
myFramesList.setSelectedValue(currentStackFrame, true);
|
||||
mySelectedFrameIndex = myFramesList.getSelectedIndex();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (event != SessionEvent.SETTINGS_CHANGED) {
|
||||
mySelectedFrameIndex = 0;
|
||||
mySelectedStack = null;
|
||||
}
|
||||
|
||||
myListenersEnabled = false;
|
||||
for (StackFramesListBuilder builder : myBuilders.values()) {
|
||||
builder.dispose();
|
||||
}
|
||||
myBuilders.clear();
|
||||
mySelectedStack = null;
|
||||
XSuspendContext suspendContext = session == null ? null : session.getSuspendContext();
|
||||
if (suspendContext == null) {
|
||||
requestClear();
|
||||
@@ -234,7 +241,7 @@ public class XFramesView extends XDebugView {
|
||||
XExecutionStack[] executionStacks = suspendContext.getExecutionStacks();
|
||||
addExecutionStacks(Arrays.asList(executionStacks));
|
||||
|
||||
XExecutionStack activeExecutionStack = suspendContext.getActiveExecutionStack();
|
||||
XExecutionStack activeExecutionStack = mySelectedStack != null ? mySelectedStack : suspendContext.getActiveExecutionStack();
|
||||
myThreadComboBox.setSelectedItem(activeExecutionStack);
|
||||
myThreadsPanel.removeAll();
|
||||
myThreadsPanel.add(myToolbar.getComponent(), BorderLayout.EAST);
|
||||
@@ -265,9 +272,6 @@ public class XFramesView extends XDebugView {
|
||||
}
|
||||
|
||||
private void updateFrames(final XExecutionStack executionStack, @NotNull XDebugSession session) {
|
||||
if (mySelectedStack == executionStack) {
|
||||
return;
|
||||
}
|
||||
if (mySelectedStack != null) {
|
||||
getOrCreateBuilder(mySelectedStack, session).stop();
|
||||
}
|
||||
@@ -275,6 +279,7 @@ public class XFramesView extends XDebugView {
|
||||
mySelectedStack = executionStack;
|
||||
if (executionStack != null) {
|
||||
StackFramesListBuilder builder = getOrCreateBuilder(executionStack, session);
|
||||
myListenersEnabled = false;
|
||||
builder.initModel(myFramesList.getModel());
|
||||
builder.start();
|
||||
}
|
||||
@@ -292,12 +297,12 @@ public class XFramesView extends XDebugView {
|
||||
return myMainPanel;
|
||||
}
|
||||
|
||||
private void processFrameSelection(@NotNull EventObject e) {
|
||||
private void processFrameSelection(XDebugSession session) {
|
||||
mySelectedFrameIndex = myFramesList.getSelectedIndex();
|
||||
Object selected = myFramesList.getSelectedValue();
|
||||
if (selected instanceof XStackFrame) {
|
||||
XDebugSession session = getSession(e);
|
||||
if (session != null) {
|
||||
session.setCurrentStackFrame(mySelectedStack, (XStackFrame)selected, myFramesList.getSelectedIndex() == 0);
|
||||
session.setCurrentStackFrame(mySelectedStack, (XStackFrame)selected, mySelectedFrameIndex == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,9 +329,7 @@ public class XFramesView extends XDebugView {
|
||||
public void run() {
|
||||
myStackFrames.addAll(stackFrames);
|
||||
addFrameListElements(stackFrames, last);
|
||||
if (myNextFrameIndex == 0) {
|
||||
selectTopFrame();
|
||||
}
|
||||
selectCurrentFrame();
|
||||
myNextFrameIndex += stackFrames.size();
|
||||
myAllFramesLoaded = last;
|
||||
if (last) {
|
||||
@@ -390,11 +393,13 @@ public class XFramesView extends XDebugView {
|
||||
myRunning = false;
|
||||
}
|
||||
|
||||
private void selectTopFrame() {
|
||||
if (!myStackFrames.isEmpty() && mySelectedStack != null) {
|
||||
XStackFrame topFrame = myStackFrames.get(0);
|
||||
myFramesList.setSelectedValue(topFrame, true);
|
||||
mySession.setCurrentStackFrame(mySelectedStack, topFrame, true);
|
||||
private void selectCurrentFrame() {
|
||||
if (mySelectedStack != null &&
|
||||
myFramesList.getSelectedIndex() != mySelectedFrameIndex &&
|
||||
myFramesList.getElementCount() > mySelectedFrameIndex &&
|
||||
myFramesList.getModel().get(mySelectedFrameIndex) != null) {
|
||||
myFramesList.setSelectedIndex(mySelectedFrameIndex);
|
||||
processFrameSelection(mySession);
|
||||
myListenersEnabled = true;
|
||||
}
|
||||
}
|
||||
@@ -411,7 +416,7 @@ public class XFramesView extends XDebugView {
|
||||
else if (!myAllFramesLoaded) {
|
||||
model.addElement(null);
|
||||
}
|
||||
selectTopFrame();
|
||||
selectCurrentFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,7 @@ import java.util.LinkedHashMap;
|
||||
*/
|
||||
@State(
|
||||
name = "ShortcutPromoterManager",
|
||||
roamingType = RoamingType.PER_PLATFORM,
|
||||
storages = {
|
||||
@Storage(
|
||||
file = StoragePathMacros.APP_CONFIG + "/promoter.xml"
|
||||
)}
|
||||
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/promoter.xml", roamingType = RoamingType.PER_PLATFORM)}
|
||||
)
|
||||
public class ShortcutPromoterManager implements ApplicationComponent, AnActionListener, ExportableApplicationComponent,
|
||||
PersistentStateComponent<Element> {
|
||||
|
||||
@@ -18,7 +18,10 @@ package git4idea.config;
|
||||
import com.intellij.dvcs.branch.DvcsBranchSync;
|
||||
import com.intellij.dvcs.branch.DvcsSyncBranchSettings;
|
||||
import com.intellij.lifecycle.PeriodicalTasksCloser;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.components.StoragePathMacros;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import git4idea.reset.GitResetMode;
|
||||
@@ -33,7 +36,7 @@ import java.util.Map;
|
||||
/**
|
||||
* Git VCS settings
|
||||
*/
|
||||
@State(name = "Git.Settings", roamingType = RoamingType.DISABLED, storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)})
|
||||
@State(name = "Git.Settings", storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)})
|
||||
public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.State>, DvcsSyncBranchSettings {
|
||||
|
||||
private static final int PREVIOUS_COMMIT_AUTHORS_LIMIT = 16; // Limit for previous commit authors
|
||||
@@ -73,7 +76,7 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
|
||||
public GitVcsApplicationSettings getAppSettings() {
|
||||
return myAppSettings;
|
||||
}
|
||||
|
||||
|
||||
public static GitVcsSettings getInstance(Project project) {
|
||||
return PeriodicalTasksCloser.getInstance().safeGetService(project, GitVcsSettings.class);
|
||||
}
|
||||
|
||||
@@ -53,12 +53,7 @@ import java.util.TreeSet;
|
||||
|
||||
@State(
|
||||
name = "SvnConfiguration",
|
||||
roamingType = RoamingType.DISABLED,
|
||||
storages = {
|
||||
@Storage(
|
||||
file = StoragePathMacros.WORKSPACE_FILE
|
||||
)
|
||||
}
|
||||
storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)}
|
||||
)
|
||||
public class SvnConfiguration implements PersistentStateComponent<SvnConfigurationState> {
|
||||
|
||||
|
||||
@@ -202,6 +202,8 @@
|
||||
use-shortcut-of="SurroundWith"/>
|
||||
<action id="GuiDesigner.Flatten" class="com.intellij.uiDesigner.actions.FlattenAction"/>
|
||||
<separator/>
|
||||
<action id="GuiDesigner.FormSource" class="com.intellij.uiDesigner.actions.ShowFormSourceAction"/>
|
||||
<separator/>
|
||||
<reference ref="VersionControlsGroup"/>
|
||||
<separator/>
|
||||
<reference ref="AddToFavorites"/>
|
||||
|
||||
+12
-8
@@ -13,16 +13,20 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.python.hierarchy.call;
|
||||
package com.intellij.uiDesigner.actions;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.uiDesigner.designSurface.GuiEditor;
|
||||
import com.intellij.uiDesigner.radComponents.RadComponent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author novokrest
|
||||
* @author Alexander Lobas
|
||||
*/
|
||||
public abstract class PyStaticCallDataManager implements PyCallDataManager {
|
||||
public static PyCallDataManager getInstance(Project project) {
|
||||
return ServiceManager.getService(project, PyStaticCallDataManager.class);
|
||||
public class ShowFormSourceAction extends AbstractGuiEditorAction {
|
||||
@Override
|
||||
protected void actionPerformed(GuiEditor editor, List<RadComponent> selection, AnActionEvent e) {
|
||||
editor.showFormSource();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package com.intellij.uiDesigner.designSurface;
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
import com.intellij.ide.DeleteProvider;
|
||||
import com.intellij.ide.highlighter.XmlFileHighlighter;
|
||||
import com.intellij.ide.palette.PaletteDragEventListener;
|
||||
import com.intellij.ide.palette.impl.PaletteManager;
|
||||
import com.intellij.lang.properties.psi.PropertiesFile;
|
||||
@@ -27,14 +28,19 @@ import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.command.undo.UndoManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogBuilder;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -215,9 +221,8 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
|
||||
|
||||
/**
|
||||
* @param file file to be edited
|
||||
* @throws java.lang.IllegalArgumentException
|
||||
* if the <code>file</code>
|
||||
* is <code>null</code> or <code>file</code> is not valid PsiFile
|
||||
* @throws java.lang.IllegalArgumentException if the <code>file</code>
|
||||
* is <code>null</code> or <code>file</code> is not valid PsiFile
|
||||
*/
|
||||
public GuiEditor(Project project, @NotNull final Module module, @NotNull final VirtualFile file) {
|
||||
LOG.assertTrue(file.isValid());
|
||||
@@ -526,7 +531,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
|
||||
|
||||
/**
|
||||
* @return the component which represents DnD layer. All currently
|
||||
* dragged (moved) component are on this layer.
|
||||
* dragged (moved) component are on this layer.
|
||||
*/
|
||||
public DragLayer getDragLayer() {
|
||||
return myDragLayer;
|
||||
@@ -534,7 +539,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
|
||||
|
||||
/**
|
||||
* @return the topmost <code>UiConainer</code> which in the root of
|
||||
* component hierarchy. This method never returns <code>null</code>.
|
||||
* component hierarchy. This method never returns <code>null</code>.
|
||||
*/
|
||||
@NotNull
|
||||
public RadRootContainer getRootContainer() {
|
||||
@@ -565,7 +570,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
|
||||
|
||||
/**
|
||||
* @return the component which represents layer with active decorators
|
||||
* such as grid edit controls, inplace editors, etc.
|
||||
* such as grid edit controls, inplace editors, etc.
|
||||
*/
|
||||
public InplaceEditingLayer getInplaceEditingLayer() {
|
||||
return myInplaceEditingLayer;
|
||||
@@ -991,6 +996,31 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
|
||||
myQuickFixManager.hideIntentionHint();
|
||||
}
|
||||
|
||||
public void showFormSource() {
|
||||
EditorFactory editorFactory = EditorFactory.getInstance();
|
||||
|
||||
Editor editor = editorFactory.createViewer(myDocument, myProject);
|
||||
|
||||
try {
|
||||
((EditorEx)editor).setHighlighter(
|
||||
new LexerEditorHighlighter(new XmlFileHighlighter(), EditorColorsManager.getInstance().getGlobalScheme()));
|
||||
|
||||
JComponent component = editor.getComponent();
|
||||
component.setPreferredSize(new Dimension(640, 480));
|
||||
|
||||
DialogBuilder dialog = new DialogBuilder(myProject);
|
||||
|
||||
dialog.title("Form - " + myFile.getPresentableName()).dimensionKey("GuiDesigner.FormSource.Dialog");
|
||||
dialog.centerPanel(component).setPreferredFocusComponent(editor.getContentComponent());
|
||||
dialog.addOkAction();
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
finally {
|
||||
editorFactory.releaseEditor(editor);
|
||||
}
|
||||
}
|
||||
|
||||
private final class MyLayeredPane extends JBLayeredPane implements Scrollable {
|
||||
/**
|
||||
* All components allocate whole pane's area.
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.intellij.uiDesigner.editor;
|
||||
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorPolicy;
|
||||
@@ -66,9 +65,6 @@ public final class UIFormEditorProvider implements FileEditorProvider, DumbAware
|
||||
}
|
||||
|
||||
@NotNull public FileEditorPolicy getPolicy() {
|
||||
return
|
||||
ApplicationManagerEx.getApplicationEx().isInternal() ?
|
||||
FileEditorPolicy.PLACE_BEFORE_DEFAULT_EDITOR : FileEditorPolicy.HIDE_DEFAULT_EDITOR;
|
||||
return FileEditorPolicy.HIDE_DEFAULT_EDITOR;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -546,6 +546,8 @@ action.GuiDesigner.GenerateMain.text=Form main()
|
||||
action.GuiDesigner.GenerateMain.description=Generate a main() method to show the UI form
|
||||
action.GuiDesigner.ReloadCustomComponents.text=Reload Custom Components
|
||||
action.GuiDesigner.ReloadCustomComponents.description=Reload modified custom component classes and recreate forms
|
||||
action.GuiDesigner.FormSource.text=Form Source
|
||||
action.GuiDesigner.FormSource.description=Show form XML content
|
||||
action.NewDialog.text=Dialog
|
||||
action.NewForm.text=GUI Form
|
||||
default.field.accessibility=Default accessibility &for UI-bound fields\:
|
||||
|
||||
@@ -19,5 +19,5 @@
|
||||
|
||||
<feedback eap-url="http://www.jetbrains.com/feedback/feedback.jsp?product=PyCharm&build=$BUILD&timezone=$TIMEZONE&eval=$EVAL"
|
||||
release-url="http://www.jetbrains.com/feedback/feedback.jsp?product=PyCharm&build=$BUILD&timezone=$TIMEZONE&eval=$EVAL"/>
|
||||
<help file="pycharm-eduhelp.jar" root="pycharm"/>
|
||||
<help file="pycharm-eduhelp.jar" root="pycharm-edu"/>
|
||||
</component>
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.jetbrains.python.documentation;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Allows you to inject quick info into python documentation provider
|
||||
*
|
||||
* @author Ilya.Kazakevich
|
||||
*/
|
||||
public interface PythonDocumentationQuickInfoProvider {
|
||||
ExtensionPointName<PythonDocumentationQuickInfoProvider> EP_NAME =
|
||||
ExtensionPointName.create("Pythonid.pythonDocumentationQuickInfoProvider");
|
||||
|
||||
/**
|
||||
* Return quick info for <strong>original</strong> element.
|
||||
*
|
||||
* @param originalElement original element
|
||||
* @return info (if exists) or null (if another provider should be checked)
|
||||
*/
|
||||
@Nullable
|
||||
String getQuickInfo(@NotNull PsiElement originalElement);
|
||||
}
|
||||
@@ -164,6 +164,8 @@ public class PyNames {
|
||||
|
||||
public static final String UNKNOWN_TYPE = "unknown";
|
||||
|
||||
public static final String UNNAMED_ELEMENT = "<unnamed>";
|
||||
|
||||
/**
|
||||
* Contains all known predefined names of "__foo__" form.
|
||||
*/
|
||||
|
||||
@@ -477,9 +477,6 @@
|
||||
<projectService serviceInterface="com.jetbrains.python.debugger.PySignatureCacheManager"
|
||||
serviceImplementation="com.jetbrains.python.debugger.PySignatureCacheManagerImpl"/>
|
||||
|
||||
<projectService serviceInterface="com.jetbrains.python.hierarchy.call.PyStaticCallDataManager"
|
||||
serviceImplementation="com.jetbrains.python.hierarchy.call.PyStaticCallDataManagerImpl"/>
|
||||
|
||||
<projectService serviceInterface="com.jetbrains.python.psi.PyPsiFacade"
|
||||
serviceImplementation="com.jetbrains.python.psi.impl.PyPsiFacadeImpl"/>
|
||||
<applicationService serviceInterface="com.jetbrains.python.packaging.PyPackageManagers"
|
||||
@@ -535,7 +532,8 @@
|
||||
|
||||
</extensions>
|
||||
|
||||
<extensionPoints>
|
||||
<extensionPoints>
|
||||
<extensionPoint qualifiedName="Pythonid.pythonDocumentationQuickInfoProvider" interface="com.jetbrains.python.documentation.PythonDocumentationQuickInfoProvider"/>
|
||||
<extensionPoint qualifiedName="Pythonid.importResolver" interface="com.jetbrains.python.psi.impl.PyImportResolver"/>
|
||||
<extensionPoint qualifiedName="Pythonid.magicLiteral" interface="com.jetbrains.python.magicLiteral.PyMagicLiteralExtensionPoint"/>
|
||||
<extensionPoint qualifiedName="Pythonid.unresolvedReferenceSkipper" interface="com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferenceSkipperExtPoint"/>
|
||||
|
||||
@@ -81,7 +81,16 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
|
||||
@NonNls private static final String EPYDOC_PREFIX = "@";
|
||||
|
||||
// provides ctrl+hover info
|
||||
public String getQuickNavigateInfo(final PsiElement element, PsiElement originalElement) {
|
||||
@Override
|
||||
@Nullable
|
||||
public String getQuickNavigateInfo(final PsiElement element, final PsiElement originalElement) {
|
||||
for (final PythonDocumentationQuickInfoProvider point : PythonDocumentationQuickInfoProvider.EP_NAME.getExtensions()) {
|
||||
String info = point.getQuickInfo(originalElement);
|
||||
if (info != null) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
if (element instanceof PyFunction) {
|
||||
PyFunction func = (PyFunction)element;
|
||||
StringBuilder cat = new StringBuilder();
|
||||
@@ -637,8 +646,9 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
|
||||
String raiseTarget = visitor.myRaiseTarget.getText();
|
||||
if (visitor.myRaiseTarget instanceof PyCallExpression) {
|
||||
final PyExpression callee = ((PyCallExpression)visitor.myRaiseTarget).getCallee();
|
||||
if (callee != null)
|
||||
if (callee != null) {
|
||||
raiseTarget = callee.getText();
|
||||
}
|
||||
}
|
||||
builder.append(" ").append(raiseTarget);
|
||||
}
|
||||
|
||||
+15
-16
@@ -19,15 +19,14 @@ import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
|
||||
import com.intellij.ide.util.treeView.NodeDescriptor;
|
||||
import com.intellij.navigation.ItemPresentation;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.roots.ui.util.CompositeAppearance;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.psi.NavigatablePsiElement;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.psi.PyClass;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
@@ -35,14 +34,14 @@ import java.awt.*;
|
||||
* Date: Jul 31, 2009
|
||||
* Time: 6:26:37 PM
|
||||
*/
|
||||
public class PyTypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
|
||||
|
||||
public PyTypeHierarchyNodeDescriptor(final NodeDescriptor parentDescriptor, @NotNull final PsiElement element, final boolean isBase) {
|
||||
public class PyHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
|
||||
public PyHierarchyNodeDescriptor(final NodeDescriptor parentDescriptor, @NotNull final PsiElement element, final boolean isBase) {
|
||||
super(element.getProject(), parentDescriptor, element, isBase);
|
||||
}
|
||||
|
||||
public PyClass getClassElement() {
|
||||
return (PyClass)myElement;
|
||||
@Nullable
|
||||
public PsiElement getPsiElement() {
|
||||
return myElement;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
@@ -55,10 +54,6 @@ public class PyTypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
|
||||
final CompositeAppearance oldText = myHighlightedText;
|
||||
|
||||
myHighlightedText = new CompositeAppearance();
|
||||
TextAttributes classNameAttributes = null;
|
||||
if (myColor != null) {
|
||||
classNameAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN);
|
||||
}
|
||||
|
||||
NavigatablePsiElement element = (NavigatablePsiElement)myElement;
|
||||
if (element == null) {
|
||||
@@ -71,10 +66,14 @@ public class PyTypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
|
||||
|
||||
final ItemPresentation presentation = element.getPresentation();
|
||||
if (presentation != null) {
|
||||
final PyClass cl = getClassElement();
|
||||
myHighlightedText.getEnding().addText(cl.getName(), classNameAttributes);
|
||||
myHighlightedText.getEnding()
|
||||
.addText(" (" + cl.getContainingFile().getName() + ")", HierarchyNodeDescriptor.getPackageNameAttributes());
|
||||
if (element instanceof PyFunction) {
|
||||
final PyClass cls = ((PyFunction)element).getContainingClass();
|
||||
if (cls != null) {
|
||||
myHighlightedText.getEnding().addText(cls.getName() + ".");
|
||||
}
|
||||
}
|
||||
myHighlightedText.getEnding().addText(presentation.getPresentableText());
|
||||
myHighlightedText.getEnding().addText(" " + presentation.getLocationString(), HierarchyNodeDescriptor.getPackageNameAttributes());
|
||||
}
|
||||
myName = myHighlightedText.getText();
|
||||
|
||||
@@ -52,10 +52,10 @@ public class PyTypeHierarchyBrowser extends TypeHierarchyBrowserBase {
|
||||
|
||||
@Nullable
|
||||
protected PsiElement getElementFromDescriptor(@NotNull HierarchyNodeDescriptor descriptor) {
|
||||
if (!(descriptor instanceof PyTypeHierarchyNodeDescriptor)) {
|
||||
if (!(descriptor instanceof PyHierarchyNodeDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
return ((PyTypeHierarchyNodeDescriptor)descriptor).getClassElement();
|
||||
return ((PyHierarchyNodeDescriptor)descriptor).getPsiElement();
|
||||
}
|
||||
|
||||
protected void createTrees(@NotNull Map<String, JTree> trees) {
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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 com.jetbrains.python.hierarchy.call;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
|
||||
/**
|
||||
* @author novokrest
|
||||
*/
|
||||
public interface PyCallDataManager {
|
||||
Collection<PsiElement> getCallees(@NotNull PyElement pyElement);
|
||||
|
||||
Collection<PsiElement> getCallers(@NotNull PyElement pyElement);
|
||||
}
|
||||
@@ -19,13 +19,11 @@ import com.intellij.ide.hierarchy.CallHierarchyBrowserBase;
|
||||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
|
||||
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
|
||||
import com.intellij.ide.util.treeView.NodeDescriptor;
|
||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.ui.PopupHandler;
|
||||
import com.jetbrains.python.hierarchy.PyHierarchyNodeDescriptor;
|
||||
import com.jetbrains.python.hierarchy.PyHierarchyUtils;
|
||||
import com.jetbrains.python.psi.PyClass;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
@@ -51,37 +49,28 @@ public class PyCallHierarchyBrowser extends CallHierarchyBrowserBase {
|
||||
@Nullable
|
||||
@Override
|
||||
protected PsiElement getElementFromDescriptor(@NotNull HierarchyNodeDescriptor descriptor) {
|
||||
if (descriptor instanceof PyCallHierarchyNodeDescriptor) {
|
||||
PyCallHierarchyNodeDescriptor nodeDescriptor = (PyCallHierarchyNodeDescriptor)descriptor;
|
||||
return nodeDescriptor.getEnclosingElement();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiElement getOpenFileElementFromDescriptor(@NotNull HierarchyNodeDescriptor descriptor) {
|
||||
if (descriptor instanceof PyCallHierarchyNodeDescriptor) {
|
||||
PyCallHierarchyNodeDescriptor nodeDescriptor = (PyCallHierarchyNodeDescriptor)descriptor;
|
||||
return nodeDescriptor.getTargetElement();
|
||||
if (descriptor instanceof PyHierarchyNodeDescriptor) {
|
||||
PyHierarchyNodeDescriptor pyDescriptor = (PyHierarchyNodeDescriptor)descriptor;
|
||||
return pyDescriptor.getPsiElement();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createTrees(@NotNull Map<String, JTree> type2TreeMap) {
|
||||
ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(GROUP_PY_CALL_HIERARCHY_POPUP);
|
||||
final JTree tree1 = createTree(false);
|
||||
PopupHandler.installPopupHandler(tree1, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance());
|
||||
final BaseOnThisFunctionAction baseOnThisFunctionAction = new BaseOnThisFunctionAction();
|
||||
baseOnThisFunctionAction
|
||||
.registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).getShortcutSet(), tree1);
|
||||
type2TreeMap.put(CALLER_TYPE, tree1);
|
||||
final ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(GROUP_PY_CALL_HIERARCHY_POPUP);
|
||||
|
||||
final JTree tree2 = createTree(false);
|
||||
PopupHandler.installPopupHandler(tree2, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance());
|
||||
baseOnThisFunctionAction
|
||||
.registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).getShortcutSet(), tree2);
|
||||
type2TreeMap.put(CALLEE_TYPE, tree2);
|
||||
final JTree callerTree = createHierarchyTree(group);
|
||||
final JTree calleeTree = createHierarchyTree(group);
|
||||
|
||||
type2TreeMap.put(CALLER_TYPE, callerTree);
|
||||
type2TreeMap.put(CALLEE_TYPE, calleeTree);
|
||||
}
|
||||
|
||||
private JTree createHierarchyTree(ActionGroup group) {
|
||||
final JTree tree = createTree(false);
|
||||
PopupHandler.installPopupHandler(tree, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance());
|
||||
return tree;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,7 +98,4 @@ public class PyCallHierarchyBrowser extends CallHierarchyBrowserBase {
|
||||
protected Comparator<NodeDescriptor> getComparator() {
|
||||
return PyHierarchyUtils.getComparator(myProject);
|
||||
}
|
||||
|
||||
public static final class BaseOnThisFunctionAction extends CallHierarchyBrowserBase.BaseOnThisMethodAction {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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 com.jetbrains.python.hierarchy.call;
|
||||
|
||||
import com.intellij.codeInsight.highlighting.HighlightManager;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
|
||||
import com.intellij.ide.util.treeView.NodeDescriptor;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.colors.EditorColors;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.markup.RangeHighlighter;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ui.util.CompositeAppearance;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
import com.intellij.ui.LayeredIcon;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author novokrest
|
||||
*/
|
||||
public class PyCallHierarchyNodeDescriptor extends HierarchyNodeDescriptor implements Navigatable {
|
||||
private int myUsageCount = 1;
|
||||
private final List<PsiReference> myReferences = new ArrayList<PsiReference>();
|
||||
private final boolean myNavigateToReference;
|
||||
|
||||
protected PyCallHierarchyNodeDescriptor(@NotNull Project project,
|
||||
@Nullable NodeDescriptor parentDescriptor,
|
||||
@NotNull PsiElement element,
|
||||
boolean isBase,
|
||||
boolean navigateToReference) {
|
||||
super(project, parentDescriptor, element, isBase);
|
||||
myNavigateToReference = navigateToReference;
|
||||
}
|
||||
|
||||
public final void incrementCount() {
|
||||
myUsageCount++;
|
||||
}
|
||||
|
||||
public final PyFunction getPyFunction() {
|
||||
return (PyFunction)myElement;
|
||||
}
|
||||
|
||||
public final PyElement getEnclosingElement() {
|
||||
return PsiTreeUtil.getNonStrictParentOfType(myElement, PyFunction.class, PyClass.class, PyFile.class);
|
||||
}
|
||||
|
||||
public final PsiElement getTargetElement() {
|
||||
return myElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return myElement != null && myElement.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update() {
|
||||
final CompositeAppearance oldText = myHighlightedText;
|
||||
final Icon oldIcon = getIcon();
|
||||
|
||||
int flags = Iconable.ICON_FLAG_VISIBILITY;
|
||||
if (isMarkReadOnly()) {
|
||||
flags |= Iconable.ICON_FLAG_READ_STATUS;
|
||||
}
|
||||
|
||||
final PsiElement element = getEnclosingElement();
|
||||
if (element == null) {
|
||||
final String invalidPrefix = IdeBundle.message("node.hierarchy.invalid");
|
||||
if (!myHighlightedText.getText().startsWith(invalidPrefix)) {
|
||||
myHighlightedText.getBeginning().addText(invalidPrefix, HierarchyNodeDescriptor.getInvalidPrefixAttributes());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean changes = super.update();
|
||||
|
||||
Icon newIcon = element.getIcon(flags);
|
||||
if (changes && myIsBase) {
|
||||
final LayeredIcon icon = new LayeredIcon(2);
|
||||
icon.setIcon(newIcon, 0);
|
||||
icon.setIcon(AllIcons.Hierarchy.Base, 1, -AllIcons.Hierarchy.Base.getIconWidth() / 2, 0);
|
||||
newIcon = icon;
|
||||
}
|
||||
setIcon(newIcon);
|
||||
|
||||
myHighlightedText = new CompositeAppearance();
|
||||
final TextAttributes mainTextAttributes = myColor != null ? null : new TextAttributes(myColor, null, null, null, Font.PLAIN);
|
||||
|
||||
PyElementVisitor visitor = new PyElementVisitor() {
|
||||
@Override
|
||||
public void visitPyClass(PyClass pyClass) {
|
||||
myHighlightedText.getEnding().addText(pyClass.getName(), mainTextAttributes);
|
||||
myHighlightedText.getEnding().addText("(" + pyClass.getContainingFile().getName() + ")",
|
||||
HierarchyNodeDescriptor.getPackageNameAttributes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyFunction(PyFunction function) {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
final PyClass pyClass = function.getContainingClass();
|
||||
if (pyClass != null) {
|
||||
buffer.append(pyClass.getName());
|
||||
buffer.append('.');
|
||||
}
|
||||
buffer.append(function.getName());
|
||||
|
||||
myHighlightedText.getEnding().addText(buffer.toString(), mainTextAttributes);
|
||||
myHighlightedText.getEnding().addText("(" + function.getContainingFile().getName() + ")",
|
||||
HierarchyNodeDescriptor.getPackageNameAttributes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyLambdaExpression(PyLambdaExpression node) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyFile(PyFile pyFile) {
|
||||
myHighlightedText.getEnding().addText(pyFile.getName(), mainTextAttributes);
|
||||
}
|
||||
};
|
||||
|
||||
element.accept(visitor);
|
||||
|
||||
if (myUsageCount > 1) {
|
||||
myHighlightedText.getEnding()
|
||||
.addText(IdeBundle.message("node.call.hierarchy.N.usages", myUsageCount), HierarchyNodeDescriptor.getUsageCountPrefixAttributes());
|
||||
}
|
||||
|
||||
myName = myHighlightedText.getText();
|
||||
if (!Comparing.equal(myHighlightedText, oldText)
|
||||
|| !Comparing.equal(getIcon(), oldIcon)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
public void addReference(final PsiReference reference) {
|
||||
myReferences.add(reference);
|
||||
}
|
||||
|
||||
public boolean hasReference(final PsiReference reference) {
|
||||
return myReferences.contains(reference);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void navigate(boolean requestFocus) {
|
||||
if (!myNavigateToReference) {
|
||||
if (myElement instanceof Navigatable && ((Navigatable)myElement).canNavigate()) {
|
||||
((Navigatable)myElement).navigate(requestFocus);
|
||||
}
|
||||
return;
|
||||
}
|
||||
final PsiReference firstReference = myReferences.get(0);
|
||||
final PsiElement element = firstReference.getElement();
|
||||
if (element == null) return;
|
||||
final PsiElement callElement = element.getParent();
|
||||
if (callElement instanceof Navigatable && ((Navigatable)callElement).canNavigate()) {
|
||||
((Navigatable)callElement).navigate(requestFocus);
|
||||
}
|
||||
else {
|
||||
final PsiFile file = callElement.getContainingFile();
|
||||
if (file == null || file.getVirtualFile() == null) return;
|
||||
FileEditorManager.getInstance(myProject).openFile(file.getVirtualFile(), requestFocus);
|
||||
}
|
||||
|
||||
Editor editor = PsiUtilBase.findEditor(callElement);
|
||||
if (editor != null) {
|
||||
HighlightManager highlightManager = HighlightManager.getInstance(myProject);
|
||||
EditorColorsManager colorsManager = EditorColorsManager.getInstance();
|
||||
TextAttributes attributes = colorsManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
|
||||
List<RangeHighlighter> highlighters = new ArrayList<RangeHighlighter>();
|
||||
for (PsiReference reference : myReferences) {
|
||||
final PsiElement eachElement = reference.getElement();
|
||||
if (eachElement != null) {
|
||||
PsiElement eachCallElement = eachElement.getParent();
|
||||
if (eachCallElement != null) {
|
||||
final TextRange textRange = eachCallElement.getTextRange();
|
||||
highlightManager
|
||||
.addRangeHighlight(editor, textRange.getStartOffset(), textRange.getEndOffset(), attributes, false, highlighters);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNavigate() {
|
||||
if (!myNavigateToReference) {
|
||||
return myElement instanceof Navigatable && ((Navigatable)myElement).canNavigate();
|
||||
}
|
||||
if (myReferences.isEmpty()) return false;
|
||||
final PsiReference reference = myReferences.get(0);
|
||||
final PsiElement callElement = reference.getElement().getParent();
|
||||
if (callElement == null || !callElement.isValid()) return false;
|
||||
if (!(callElement instanceof Navigatable) || !((Navigatable)callElement).canNavigate()) {
|
||||
final PsiFile file = callElement.getContainingFile();
|
||||
if (file == null) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNavigateToSource() {
|
||||
return canNavigate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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 com.jetbrains.python.hierarchy.call;
|
||||
|
||||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
|
||||
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.jetbrains.python.hierarchy.PyHierarchyNodeDescriptor;
|
||||
import com.jetbrains.python.psi.PyClass;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author novokrest
|
||||
*/
|
||||
public abstract class PyCallHierarchyTreeStructureBase extends HierarchyTreeStructure {
|
||||
private final String myScopeType;
|
||||
|
||||
public PyCallHierarchyTreeStructureBase(Project project, PsiElement element, String currentScopeType) {
|
||||
super(project, new PyHierarchyNodeDescriptor(null, element, true));
|
||||
myScopeType = currentScopeType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract List<PsiElement> getChildren(@NotNull PyElement element);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Object[] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) {
|
||||
final List<PyHierarchyNodeDescriptor> descriptors = new ArrayList<PyHierarchyNodeDescriptor>();
|
||||
if (descriptor instanceof PyHierarchyNodeDescriptor) {
|
||||
final PyHierarchyNodeDescriptor pyDescriptor = (PyHierarchyNodeDescriptor)descriptor;
|
||||
final PsiElement element = pyDescriptor.getPsiElement();
|
||||
final boolean isCallable = element instanceof PyFunction || element instanceof PyClass || element instanceof PyFile;
|
||||
HierarchyNodeDescriptor nodeDescriptor = getBaseDescriptor();
|
||||
if (!(element instanceof PyElement) || !isCallable || nodeDescriptor == null) {
|
||||
return ArrayUtil.EMPTY_OBJECT_ARRAY;
|
||||
}
|
||||
|
||||
final List<PsiElement> children = getChildren((PyElement)element);
|
||||
|
||||
final HashMap<PsiElement, PyHierarchyNodeDescriptor> callerToDescriptorMap = new HashMap<PsiElement, PyHierarchyNodeDescriptor>();
|
||||
PsiElement baseClass = element instanceof PyFunction ? ((PyFunction)element).getContainingClass() : null;
|
||||
|
||||
for (PsiElement caller : children) {
|
||||
if (isInScope(baseClass, caller, myScopeType)) {
|
||||
PyHierarchyNodeDescriptor callerDescriptor = callerToDescriptorMap.get(caller);
|
||||
if (callerDescriptor == null) {
|
||||
callerDescriptor = new PyHierarchyNodeDescriptor(descriptor, caller, false);
|
||||
callerToDescriptorMap.put(caller, callerDescriptor);
|
||||
descriptors.add(callerDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return ArrayUtil.toObjectArray(descriptors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlwaysShowPlus() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -15,74 +15,28 @@
|
||||
*/
|
||||
package com.jetbrains.python.hierarchy.call;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
|
||||
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.jetbrains.python.psi.PyClass;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author novokrest
|
||||
*/
|
||||
public class PyCalleeFunctionTreeStructure extends HierarchyTreeStructure {
|
||||
private final String myScopeType;
|
||||
|
||||
public class PyCalleeFunctionTreeStructure extends PyCallHierarchyTreeStructureBase {
|
||||
public PyCalleeFunctionTreeStructure(Project project, PsiElement element, String currentScopeType) {
|
||||
super(project, new PyCallHierarchyNodeDescriptor(project, null, element, true, false));
|
||||
myScopeType = currentScopeType;
|
||||
super(project, element, currentScopeType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Object[] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) {
|
||||
final PyElement element = ((PyCallHierarchyNodeDescriptor)descriptor).getEnclosingElement();
|
||||
final boolean isCallable = element instanceof PyFunction || element instanceof PyClass || element instanceof PyFile;
|
||||
HierarchyNodeDescriptor nodeDescriptor = getBaseDescriptor();
|
||||
if (!isCallable || nodeDescriptor == null) {
|
||||
return ArrayUtil.EMPTY_OBJECT_ARRAY;
|
||||
}
|
||||
|
||||
final List<PsiElement> callees = Lists.newArrayList();
|
||||
|
||||
PyCallDataManager[] functionManagers = {
|
||||
// TODO: Add dynamic call data manager
|
||||
PyStaticCallDataManager.getInstance(myProject),
|
||||
};
|
||||
|
||||
for (PyCallDataManager functionManager : functionManagers) {
|
||||
callees.addAll(functionManager.getCallees(element));
|
||||
}
|
||||
|
||||
final Map<PsiElement, PyCallHierarchyNodeDescriptor> calleeToDescriptorMap = new HashMap<PsiElement, PyCallHierarchyNodeDescriptor>();
|
||||
final List<PyCallHierarchyNodeDescriptor> descriptors = Lists.newArrayList();
|
||||
PsiElement baseClass = element instanceof PyFunction ? ((PyFunction)element).getContainingClass() : null;
|
||||
|
||||
for (PsiElement callee : callees) {
|
||||
if (baseClass != null && !isInScope(baseClass, callee, myScopeType)) continue;
|
||||
|
||||
PyCallHierarchyNodeDescriptor calleeDescriptor = calleeToDescriptorMap.get(callee);
|
||||
if (calleeDescriptor == null) {
|
||||
calleeDescriptor = new PyCallHierarchyNodeDescriptor(myProject, null, callee, false, false);
|
||||
calleeToDescriptorMap.put(callee, calleeDescriptor);
|
||||
descriptors.add(calleeDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
return ArrayUtil.toObjectArray(descriptors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlwaysShowPlus() {
|
||||
return true;
|
||||
protected List<PsiElement> getChildren(@NotNull PyElement element) {
|
||||
final List<PsiElement> callees = new ArrayList<PsiElement>();
|
||||
// TODO: Add callees from the dynamic call data manager
|
||||
callees.addAll(PyStaticCallHierarchyUtil.getCallees(element));
|
||||
return callees;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,73 +15,28 @@
|
||||
*/
|
||||
package com.jetbrains.python.hierarchy.call;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
|
||||
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.jetbrains.python.psi.PyClass;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author novokrest
|
||||
*/
|
||||
public class PyCallerFunctionTreeStructure extends HierarchyTreeStructure {
|
||||
private final String myScopeType;
|
||||
|
||||
public class PyCallerFunctionTreeStructure extends PyCallHierarchyTreeStructureBase {
|
||||
public PyCallerFunctionTreeStructure(Project project, PsiElement element, String currentScopeType) {
|
||||
super(project, new PyCallHierarchyNodeDescriptor(project, null, element, true, false));
|
||||
myScopeType = currentScopeType;
|
||||
super(project, element, currentScopeType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Object[] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) {
|
||||
final PyElement element = ((PyCallHierarchyNodeDescriptor)descriptor).getEnclosingElement();
|
||||
final boolean isCallable = element instanceof PyFunction || element instanceof PyClass || element instanceof PyFile;
|
||||
HierarchyNodeDescriptor nodeDescriptor = getBaseDescriptor();
|
||||
if (!isCallable || nodeDescriptor == null) {
|
||||
return ArrayUtil.EMPTY_OBJECT_ARRAY;
|
||||
}
|
||||
|
||||
final List<PsiElement> callers = Lists.newArrayList();
|
||||
|
||||
PyCallDataManager[] functionManagers = {
|
||||
// TODO: Add dynamic call data manager
|
||||
PyStaticCallDataManager.getInstance(myProject),
|
||||
};
|
||||
|
||||
for (PyCallDataManager functionManager : functionManagers) {
|
||||
callers.addAll(functionManager.getCallers(element));
|
||||
}
|
||||
|
||||
final HashMap<PsiElement, PyCallHierarchyNodeDescriptor> callerToDescriptorMap = new HashMap<PsiElement, PyCallHierarchyNodeDescriptor>();
|
||||
final List<PyCallHierarchyNodeDescriptor> descriptors = Lists.newArrayList();
|
||||
PsiElement baseClass = element instanceof PyFunction ? ((PyFunction)element).getContainingClass() : null;
|
||||
|
||||
for (PsiElement caller : callers) {
|
||||
if (baseClass != null && !isInScope(baseClass, caller, myScopeType)) continue;
|
||||
|
||||
PyCallHierarchyNodeDescriptor callerDescriptor = callerToDescriptorMap.get(caller);
|
||||
if (callerDescriptor == null) {
|
||||
callerDescriptor = new PyCallHierarchyNodeDescriptor(myProject, null, caller, false, false);
|
||||
callerToDescriptorMap.put(caller, callerDescriptor);
|
||||
descriptors.add(callerDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
return ArrayUtil.toObjectArray(descriptors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlwaysShowPlus() {
|
||||
return true;
|
||||
protected List<PsiElement> getChildren(@NotNull PyElement element) {
|
||||
final List<PsiElement> callers = new ArrayList<PsiElement>();
|
||||
// TODO: Add callers from the dynamic call data manager
|
||||
callers.addAll(PyStaticCallHierarchyUtil.getCallers(element));
|
||||
return callers;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user