Package liveplugin.pluginrunner

Source Code of liveplugin.pluginrunner.ScalaPluginRunner

package liveplugin.pluginrunner;

import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.Function;
import com.intellij.util.PathUtil;
import liveplugin.MyFileUtil;
import scala.tools.nsc.Settings;
import scala.tools.nsc.interpreter.IMain;
import scala.tools.nsc.interpreter.Results;
import scala.tools.nsc.settings.MutableSettings;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;

import static com.intellij.openapi.application.PathManager.getLibPath;
import static com.intellij.openapi.application.PathManager.getPluginsPath;
import static com.intellij.openapi.util.text.StringUtil.join;
import static com.intellij.util.containers.ContainerUtil.map;
import static java.io.File.pathSeparator;
import static java.util.Arrays.asList;
import static liveplugin.MyFileUtil.*;
import static liveplugin.pluginrunner.PluginRunner.ClasspathAddition.findClasspathAdditions;

/**
* This class should not be loaded unless scala libs are on classpath.
*/
class ScalaPluginRunner implements PluginRunner {
  private static final String MAIN_SCRIPT = "plugin.scala";
  private static final String SCALA_ADD_TO_CLASSPATH_KEYWORD = "// " + ADD_TO_CLASSPATH_KEYWORD;

  private static final StringWriter interpreterOutput = new StringWriter();
  private static final Object interpreterLock = new Object();

  private final ErrorReporter errorReporter;
  private final Map<String, String> environment;


  public ScalaPluginRunner(ErrorReporter errorReporter, Map<String, String> environment) {
    this.errorReporter = errorReporter;
    this.environment = environment;
  }

  @Override public boolean canRunPlugin(String pathToPluginFolder) {
    return findSingleFileIn(pathToPluginFolder, MAIN_SCRIPT) != null;
  }

  @Override public void runPlugin(String pathToPluginFolder, final String pluginId,
                                  Map<String, ?> binding, Function<Runnable, Void> runOnEDTCallback) {
    final File scriptFile = MyFileUtil.findSingleFileIn(pathToPluginFolder, ScalaPluginRunner.MAIN_SCRIPT);
    assert scriptFile != null;

    final IMain interpreter;
    synchronized (interpreterLock) {
      try {
        environment.put("PLUGIN_PATH", pathToPluginFolder);

        List<String> additionalPaths = findClasspathAdditions(readLines(asUrl(scriptFile)), SCALA_ADD_TO_CLASSPATH_KEYWORD, environment, new Function<String, Void>() {
          @Override public Void fun(String path) {
            errorReporter.addLoadingError(pluginId, "Couldn't find dependency '" + path + "'");
            return null;
          }
        });
        String classpath = createInterpreterClasspath(additionalPaths);
        interpreter = initInterpreter(classpath);

      } catch (Exception e) {
        errorReporter.addLoadingError("Failed to init scala interpreter", e);
        return;
      } catch (LinkageError e) {
        errorReporter.addLoadingError("Failed to init scala interpreter", e);
        return;
      }

      interpreterOutput.getBuffer().delete(0, interpreterOutput.getBuffer().length());
      for (Map.Entry<String, ?> entry : binding.entrySet()) {
        interpreter.bindValue(entry.getKey(), entry.getValue());
      }
    }

    runOnEDTCallback.fun(new Runnable() {
      @Override public void run() {
        synchronized (interpreterLock) {
          Results.Result result;
          try {
            result = interpreter.interpret(FileUtil.loadFile(scriptFile));
          } catch (LinkageError e) {
            errorReporter.addLoadingError(pluginId, "Error linking script file: " + scriptFile);
            return;
          } catch (Exception e) {
            errorReporter.addLoadingError(pluginId, "Error reading script file: " + scriptFile);
            return;
          }

          if (!(result instanceof Results.Success$)) {
            errorReporter.addRunningError(pluginId, interpreterOutput.toString());
          }
        }
      }
    });
  }

  @Override public String scriptName() {
    return MAIN_SCRIPT;
  }

  private static IMain initInterpreter(String interpreterClasspath) throws ClassNotFoundException {
    Settings settings = new Settings();
    MutableSettings.PathSetting bootClasspath = (MutableSettings.PathSetting) settings.bootclasspath();
    bootClasspath.append(interpreterClasspath);

    ((MutableSettings.BooleanSetting) settings.usejavacp()).tryToSetFromPropertyValue("true");

    return new IMain(settings, new PrintWriter(interpreterOutput));
  }

  private static String createInterpreterClasspath(List<String> additionalPaths) throws ClassNotFoundException {
    Function<File, String> toAbsolutePath = new Function<File, String>() {
      @Override public String fun(File it) {
        return it.getAbsolutePath();
      }
    };

    String compilerPath = PathUtil.getJarPathForClass(Class.forName("scala.tools.nsc.Interpreter"));
    String scalaLibPath = PathUtil.getJarPathForClass(Class.forName("scala.Some"));
    String intellijLibPath = join(map(withDefault(new File[0], new File(getLibPath()).listFiles()), toAbsolutePath), pathSeparator);
    String intellijPluginsPath = join(map(withDefault(new File[0], new File(getPluginsPath()).listFiles()), toAbsolutePath), pathSeparator);
    String livePluginPath = PathManager.getResourceRoot(ScalaPluginRunner.class, "/liveplugin/"); // this is only useful when running liveplugin from IDE (it's not packed into jar)
    return join(asList(compilerPath, scalaLibPath, livePluginPath, intellijLibPath, intellijPluginsPath), pathSeparator) +
        pathSeparator + join(additionalPaths, pathSeparator);
  }

  private static <T> T withDefault(T defaultValue, T value) {
    return value == null ? defaultValue : value;
  }
}
TOP

Related Classes of liveplugin.pluginrunner.ScalaPluginRunner

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.