mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
terminal: show confirmation dialog on attempt to close it if there are running processes (IDEA-205690)
This commit is contained in:
@@ -22,5 +22,6 @@
|
||||
<orderEntry type="library" name="jediterm-pty" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.lang.impl" />
|
||||
<orderEntry type="module" module-name="intellij.platform.configurationStore.impl" scope="TEST" />
|
||||
<orderEntry type="library" name="winp" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -5,8 +5,13 @@ import com.intellij.execution.TerminateRemoteProcessDialog
|
||||
import com.intellij.execution.process.NopProcessHandler
|
||||
import com.intellij.execution.ui.BaseContentCloseListener
|
||||
import com.intellij.execution.ui.RunContentManagerImpl
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.ui.content.Content
|
||||
import com.intellij.util.ObjectUtils
|
||||
import com.jediterm.terminal.ProcessTtyConnector
|
||||
import org.jetbrains.plugins.terminal.arrangement.ProcessInfoUtil
|
||||
|
||||
class TerminalTabCloseListener(val content: Content,
|
||||
val project: Project) : BaseContentCloseListener(content, project) {
|
||||
@@ -21,6 +26,15 @@ class TerminalTabCloseListener(val content: Content,
|
||||
if (widget == null || !widget.isSessionRunning) {
|
||||
return true
|
||||
}
|
||||
val connector = widget.ttyConnector as? ProcessTtyConnector
|
||||
try {
|
||||
if (connector != null && !TerminalUtil.hasRunningCommands(connector)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
val proxy = NopProcessHandler().apply { startNotify() }
|
||||
// don't show 'disconnect' button
|
||||
proxy.putUserData(RunContentManagerImpl.ALWAYS_USE_DEFAULT_STOPPING_BEHAVIOUR_KEY, true)
|
||||
@@ -32,3 +46,5 @@ class TerminalTabCloseListener(val content: Content,
|
||||
return project === this.project && closeQuery(this.content, true)
|
||||
}
|
||||
}
|
||||
|
||||
private val LOG = logger<TerminalTabCloseListener>()
|
||||
|
||||
@@ -1,15 +1,36 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.terminal;
|
||||
|
||||
import com.intellij.execution.process.OSProcessUtil;
|
||||
import com.intellij.execution.process.UnixProcessManager;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.terminal.JBTerminalWidget;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.execution.ParametersListUtil;
|
||||
import com.jediterm.terminal.ProcessTtyConnector;
|
||||
import com.pty4j.windows.WinPtyProcess;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.winp.WinProcess;
|
||||
import org.jvnet.winp.WinpException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class TerminalUtil {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(TerminalUtil.class);
|
||||
|
||||
private TerminalUtil() {}
|
||||
|
||||
@NotNull
|
||||
@@ -33,4 +54,52 @@ public class TerminalUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean hasRunningCommands(@NotNull ProcessTtyConnector connector) throws IllegalStateException {
|
||||
Process process = connector.getProcess();
|
||||
if (!process.isAlive()) return false;
|
||||
if (SystemInfo.isUnix) {
|
||||
int shellPid = OSProcessUtil.getProcessID(process);
|
||||
MultiMap<Integer, Integer> pidToChildPidsMap = MultiMap.create();
|
||||
UnixProcessManager.processPSOutput(UnixProcessManager.getPSCmd(false, false), new Processor<String>() {
|
||||
@Override
|
||||
public boolean process(String s) {
|
||||
StringTokenizer st = new StringTokenizer(s, " ");
|
||||
int parentPid = Integer.parseInt(st.nextToken());
|
||||
int pid = Integer.parseInt(st.nextToken());
|
||||
pidToChildPidsMap.putValue(parentPid, pid);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return !pidToChildPidsMap.get(shellPid).isEmpty();
|
||||
}
|
||||
else if (SystemInfo.isWindows) {
|
||||
WinPtyProcess winPty = (WinPtyProcess)process;
|
||||
try {
|
||||
String executable = FileUtil.toSystemIndependentName(StringUtil.notNullize(getExecutable(winPty.getChildProcessId())));
|
||||
int consoleProcessCount = winPty.getConsoleProcessCount();
|
||||
if (executable.endsWith("/Git/bin/bash.exe")) {
|
||||
return consoleProcessCount > 3;
|
||||
}
|
||||
return consoleProcessCount > 2;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Unknown OS: " + SystemInfo.OS_NAME);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getExecutable(int pid) {
|
||||
WinProcess winProcess = new WinProcess(pid);
|
||||
String commandLine;
|
||||
try {
|
||||
commandLine = winProcess.getCommandLine();
|
||||
}
|
||||
catch (WinpException e) {
|
||||
LOG.error(e);
|
||||
return null;
|
||||
}
|
||||
return ContainerUtil.getFirstItem(ParametersListUtil.parse(commandLine));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user