From f1f889df14b99c21bf4d71845ee9ae84c2a8490e Mon Sep 17 00:00:00 2001 From: hstyi Date: Thu, 10 Apr 2025 11:45:27 +0800 Subject: [PATCH] chore: improve terminal close (#484) --- .../kotlin/app/termora/LocalTerminalTab.kt | 48 +++++++++++++++++++ src/main/kotlin/app/termora/TerminalTab.kt | 3 ++ .../termora/terminal/PtyProcessConnector.kt | 2 +- src/main/resources/i18n/messages.properties | 1 + .../resources/i18n/messages_zh_CN.properties | 2 +- .../resources/i18n/messages_zh_TW.properties | 1 + 6 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/app/termora/LocalTerminalTab.kt b/src/main/kotlin/app/termora/LocalTerminalTab.kt index 93d1df1..a6dca01 100644 --- a/src/main/kotlin/app/termora/LocalTerminalTab.kt +++ b/src/main/kotlin/app/termora/LocalTerminalTab.kt @@ -1,12 +1,22 @@ package app.termora import app.termora.terminal.PtyConnector +import app.termora.terminal.PtyConnectorDelegate +import app.termora.terminal.PtyProcessConnector import org.apache.commons.io.Charsets +import org.slf4j.LoggerFactory import java.nio.charset.StandardCharsets +import javax.swing.JOptionPane +import javax.swing.SwingUtilities +import kotlin.jvm.optionals.getOrNull class LocalTerminalTab(windowScope: WindowScope, host: Host) : PtyHostTerminalTab(windowScope, host) { + companion object { + private val log = LoggerFactory.getLogger(LocalTerminalTab::class.java) + } + override suspend fun openPtyConnector(): PtyConnector { val winSize = terminalPanel.winSize() val ptyConnector = PtyConnectorFactory.getInstance().createPtyConnector( @@ -18,4 +28,42 @@ class LocalTerminalTab(windowScope: WindowScope, host: Host) : return ptyConnector } + + override fun willBeClose(): Boolean { + val ptyProcessConnector = getPtyProcessConnector() ?: return true + val process = ptyProcessConnector.process + var consoleProcessCount = 0 + + try { + val processHandle = ProcessHandle.of(process.pid()).getOrNull() + if (processHandle != null) { + consoleProcessCount = processHandle.children().count().toInt() + } + } catch (e: Exception) { + if (log.isErrorEnabled) { + log.error(e.message, e) + } + } + + // 没有正在运行的进程 + if (consoleProcessCount < 1) return true + + val owner = SwingUtilities.getWindowAncestor(terminalPanel) ?: return true + return OptionPane.showConfirmDialog( + owner, + I18n.getString("termora.tabbed.local-tab.close-prompt"), + messageType = JOptionPane.INFORMATION_MESSAGE, + optionType = JOptionPane.OK_CANCEL_OPTION + ) == JOptionPane.OK_OPTION + } + + + private fun getPtyProcessConnector(): PtyProcessConnector? { + var p = getPtyConnector() as PtyConnector? + while (p != null) { + if (p is PtyProcessConnector) return p + if (p is PtyConnectorDelegate) p = p.ptyConnector + } + return null + } } \ No newline at end of file diff --git a/src/main/kotlin/app/termora/TerminalTab.kt b/src/main/kotlin/app/termora/TerminalTab.kt index 6847817..6933cd0 100644 --- a/src/main/kotlin/app/termora/TerminalTab.kt +++ b/src/main/kotlin/app/termora/TerminalTab.kt @@ -43,6 +43,9 @@ interface TerminalTab : Disposable, DataProvider { */ fun canClose(): Boolean = true + /** + * 返回 true 表示可以关闭 + */ fun willBeClose(): Boolean = true /** diff --git a/src/main/kotlin/app/termora/terminal/PtyProcessConnector.kt b/src/main/kotlin/app/termora/terminal/PtyProcessConnector.kt index 035d47f..c91af3f 100644 --- a/src/main/kotlin/app/termora/terminal/PtyProcessConnector.kt +++ b/src/main/kotlin/app/termora/terminal/PtyProcessConnector.kt @@ -6,7 +6,7 @@ import java.io.InputStreamReader import java.nio.charset.Charset import java.nio.charset.StandardCharsets -class PtyProcessConnector(private val process: PtyProcess, private val charset: Charset = StandardCharsets.UTF_8) : +class PtyProcessConnector(val process: PtyProcess, private val charset: Charset = StandardCharsets.UTF_8) : StreamPtyConnector(process.inputStream, process.outputStream) { private val reader = InputStreamReader(input) diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties index 61c582a..990dc2f 100644 --- a/src/main/resources/i18n/messages.properties +++ b/src/main/resources/i18n/messages.properties @@ -231,6 +231,7 @@ termora.tabbed.contextmenu.close=Close termora.tabbed.contextmenu.close-other-tabs=Close Other Tabs termora.tabbed.contextmenu.close-all-tabs=Close All Tabs termora.tabbed.contextmenu.reconnect=Reconnect +termora.tabbed.local-tab.close-prompt=Do you want to terminal a running process in this terminal? # Terminal logger termora.terminal-logger=Terminal Logger diff --git a/src/main/resources/i18n/messages_zh_CN.properties b/src/main/resources/i18n/messages_zh_CN.properties index 0e442ea..5ebe503 100644 --- a/src/main/resources/i18n/messages_zh_CN.properties +++ b/src/main/resources/i18n/messages_zh_CN.properties @@ -220,7 +220,7 @@ termora.tabbed.contextmenu.close=关闭 termora.tabbed.contextmenu.close-other-tabs=关闭其他标签页 termora.tabbed.contextmenu.close-all-tabs=关闭所有标签页 termora.tabbed.contextmenu.reconnect=重新连接 - +termora.tabbed.local-tab.close-prompt=你想要终止这个终端中正在运行的进程吗? # Terminal logger diff --git a/src/main/resources/i18n/messages_zh_TW.properties b/src/main/resources/i18n/messages_zh_TW.properties index 999ee32..d7e2edf 100644 --- a/src/main/resources/i18n/messages_zh_TW.properties +++ b/src/main/resources/i18n/messages_zh_TW.properties @@ -216,6 +216,7 @@ termora.tabbed.contextmenu.close=關閉 termora.tabbed.contextmenu.close-other-tabs=關閉其他標籤頁 termora.tabbed.contextmenu.close-all-tabs=關閉所有標籤 termora.tabbed.contextmenu.reconnect=重新連接 +termora.tabbed.local-tab.close-prompt=你想要終止這個終端機中正在運作的進程嗎?