blob: 8a5f75b365947337cef80f3875f22a12c9a28b20 [file] [log] [blame]
package org.jetbrains.plugins.terminal;
import com.intellij.execution.TaskExecutor;
import com.intellij.execution.configurations.EncodingEnvironmentUtil;
import com.intellij.execution.process.*;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.containers.HashMap;
import com.jediterm.pty.PtyProcessTtyConnector;
import com.jediterm.terminal.TtyConnector;
import com.pty4j.PtyProcess;
import com.pty4j.util.PtyUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* @author traff
*/
public class LocalTerminalDirectRunner extends AbstractTerminalRunner<PtyProcess> {
private static final Logger LOG = Logger.getInstance(LocalTerminalDirectRunner.class);
private final Charset myDefaultCharset;
public LocalTerminalDirectRunner(Project project) {
super(project);
myDefaultCharset = Charset.forName("UTF-8");
}
private static boolean hasLoginArgument(String name) {
return name.equals("bash") || name.equals("sh") || name.equals("zsh");
}
private static String getShellName(String path) {
return new File(path).getName();
}
private static File findRCFile() {
try {
final String folder = PtyUtil.getPtyLibFolderPath();
if (folder != null) {
File rcFile = new File(folder, "jediterm.in");
if (rcFile.exists()) {
return rcFile;
}
}
}
catch (Exception e) {
LOG.warn("Unable to get JAR folder", e);
}
return null;
}
@NotNull
public static LocalTerminalDirectRunner createTerminalRunner(Project project) {
return new LocalTerminalDirectRunner(project);
}
@Override
protected PtyProcess createProcess(@Nullable String directory) throws ExecutionException {
Map<String, String> envs = new HashMap<String, String>(System.getenv());
envs.put("TERM", "xterm-256color");
EncodingEnvironmentUtil.fixDefaultEncodingIfMac(envs, getProject());
try {
return PtyProcess.exec(getCommand(), envs, directory != null ? directory : currentProjectFolder());
}
catch (IOException e) {
throw new ExecutionException(e);
}
}
private String currentProjectFolder() {
final ProjectRootManager projectRootManager = ProjectRootManager.getInstance(myProject);
final VirtualFile[] roots = projectRootManager.getContentRoots();
if (roots.length == 1) {
roots[0].getCanonicalPath();
}
final VirtualFile baseDir = myProject.getBaseDir();
return baseDir == null ? null : baseDir.getCanonicalPath();
}
@Override
protected ProcessHandler createProcessHandler(final PtyProcess process) {
return new PtyProcessHandler(process);
}
@Override
protected TtyConnector createTtyConnector(PtyProcess process) {
return new PtyProcessTtyConnector(process, myDefaultCharset);
}
@Override
protected String getTerminalConnectionName(PtyProcess process) {
return "Local Terminal";
}
public String[] getCommand() {
String[] command;
String shellPath = TerminalOptionsProvider.getInstance().getShellPath();
if (SystemInfo.isUnix) {
File rcFile = findRCFile();
String shellName = getShellName(shellPath);
if (rcFile != null && (shellName.equals("bash") || shellName.equals("sh"))) {
command = new String[]{shellPath, "--rcfile", rcFile.getAbsolutePath(), "-i"};
}
else if (hasLoginArgument(shellName)) {
command = new String[]{shellPath, "--login"};
}
else {
command = shellPath.split(" ");
}
}
else {
command = new String[]{shellPath};
}
return command;
}
private static class PtyProcessHandler extends ProcessHandler implements TaskExecutor {
private final PtyProcess myProcess;
private final ProcessWaitFor myWaitFor;
public PtyProcessHandler(PtyProcess process) {
myProcess = process;
myWaitFor = new ProcessWaitFor(process, this);
}
@Override
public void startNotify() {
addProcessListener(new ProcessAdapter() {
@Override
public void startNotified(ProcessEvent event) {
try {
myWaitFor.setTerminationCallback(new Consumer<Integer>() {
@Override
public void consume(Integer integer) {
notifyProcessTerminated(integer);
}
});
}
finally {
removeProcessListener(this);
}
}
});
super.startNotify();
}
@Override
protected void destroyProcessImpl() {
myProcess.destroy();
}
@Override
protected void detachProcessImpl() {
destroyProcessImpl();
}
@Override
public boolean detachIsDefault() {
return false;
}
@Override
public boolean isSilentlyDestroyOnClose() {
return true;
}
@Nullable
@Override
public OutputStream getProcessInput() {
return myProcess.getOutputStream();
}
@Override
public Future<?> executeTask(Runnable task) {
return executeOnPooledThread(task);
}
protected static Future<?> executeOnPooledThread(Runnable task) {
final Application application = ApplicationManager.getApplication();
if (application != null) {
return application.executeOnPooledThread(task);
}
return BaseOSProcessHandler.ExecutorServiceHolder.submit(task);
}
}
}