fix: terminal exception caused by reconnection

This commit is contained in:
hstyi
2025-08-01 18:10:34 +08:00
committed by GitHub
parent 79ed6d3858
commit 8ba74f0846
12 changed files with 53 additions and 31 deletions

View File

@@ -4,7 +4,7 @@ plugins {
project.version = "0.0.4" project.version = "0.0.5"
dependencies { dependencies {

View File

@@ -1,9 +1,6 @@
package app.termora.plugins.serial package app.termora.plugins.serial
import app.termora.Host import app.termora.*
import app.termora.Icons
import app.termora.PtyHostTerminalTab
import app.termora.WindowScope
import app.termora.terminal.PtyConnector import app.termora.terminal.PtyConnector
import org.apache.commons.io.Charsets import org.apache.commons.io.Charsets
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
@@ -11,6 +8,8 @@ import javax.swing.Icon
class SerialTerminalTab(windowScope: WindowScope, host: Host) : class SerialTerminalTab(windowScope: WindowScope, host: Host) :
PtyHostTerminalTab(windowScope, host) { PtyHostTerminalTab(windowScope, host) {
override suspend fun openPtyConnector(): PtyConnector { override suspend fun openPtyConnector(): PtyConnector {
val serialPort = Serials.openPort(host) val serialPort = Serials.openPort(host)
return SerialPortPtyConnector( return SerialPortPtyConnector(
@@ -19,6 +18,10 @@ class SerialTerminalTab(windowScope: WindowScope, host: Host) :
) )
} }
override fun createReconnectTerminalTab(): TerminalTab {
return SerialTerminalTab(windowScope, host)
}
override fun getIcon(): Icon { override fun getIcon(): Icon {
return Icons.plugin return Icons.plugin
} }

View File

@@ -27,7 +27,7 @@ abstract class HostTerminalTab(
protected val terminalTabbedManager protected val terminalTabbedManager
get() = AnActionEvent(getJComponent(), StringUtils.EMPTY, EventObject(getJComponent())) get() = AnActionEvent(getJComponent(), StringUtils.EMPTY, EventObject(getJComponent()))
.getData(DataProviders.TerminalTabbedManager) .getData(DataProviders.TerminalTabbedManager)
protected val coroutineScope by lazy { CoroutineScope(SupervisorJob() + Dispatchers.Swing) } protected val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Swing)
protected val terminalModel get() = terminal.getTerminalModel() protected val terminalModel get() = terminal.getTerminalModel()
protected var unread = false protected var unread = false
set(value) { set(value) {

View File

@@ -173,10 +173,21 @@ abstract class PtyHostTerminalTab(
} }
override fun reconnect() { override fun reconnect() {
stop() val manager = terminalTabbedManager ?: return
start() val index = manager.indexOfTerminalTab(this)
if (index < 0) return
val tab = createReconnectTerminalTab()
manager.addTerminalTab(index, tab, true)
manager.closeTerminalTab(this, true)
if (tab is HostTerminalTab) {
tab.start()
}
} }
protected abstract fun createReconnectTerminalTab(): TerminalTab
override fun getJComponent(): JComponent { override fun getJComponent(): JComponent {
return terminalPanel return terminalPanel
} }

View File

@@ -367,6 +367,10 @@ class TerminalTabbed(
} }
} }
override fun indexOfTerminalTab(tab: TerminalTab):Int {
return tabbedPane.indexOfComponent(tab.getJComponent())
}
private inner class SwitchFindEverywhereResult( private inner class SwitchFindEverywhereResult(
private val title: String, private val title: String,
private val icon: Icon?, private val icon: Icon?,

View File

@@ -8,4 +8,5 @@ interface TerminalTabbedManager {
fun setSelectedTerminalTab(tab: TerminalTab) fun setSelectedTerminalTab(tab: TerminalTab)
fun closeTerminalTab(tab: TerminalTab, disposable: Boolean = true) fun closeTerminalTab(tab: TerminalTab, disposable: Boolean = true)
fun refreshTerminalTabs() fun refreshTerminalTabs()
fun indexOfTerminalTab(tab: TerminalTab): Int
} }

View File

@@ -62,6 +62,9 @@ class LocalTerminalTab(windowScope: WindowScope, host: Host) :
) == JOptionPane.OK_OPTION ) == JOptionPane.OK_OPTION
} }
override fun createReconnectTerminalTab(): TerminalTab {
return LocalTerminalTab(windowScope, host)
}
private fun getPtyProcessConnector(): PtyProcessConnector? { private fun getPtyProcessConnector(): PtyProcessConnector? {
var p = getPtyConnector() as PtyConnector? var p = getPtyConnector() as PtyConnector?

View File

@@ -185,6 +185,10 @@ class SFTPPtyTerminalTab(windowScope: WindowScope, host: Host) : PtyHostTerminal
return Icons.fileFormat return Icons.fileFormat
} }
override fun createReconnectTerminalTab(): TerminalTab {
return SFTPPtyTerminalTab(windowScope, host)
}
override fun sendStartupCommand(ptyConnector: PtyConnector, bytes: ByteArray) { override fun sendStartupCommand(ptyConnector: PtyConnector, bytes: ByteArray) {
// Nothing // Nothing
} }

View File

@@ -54,6 +54,10 @@ class SSHTerminalTab(
return mutex.isLocked.not() return mutex.isLocked.not()
} }
override fun createReconnectTerminalTab(): TerminalTab {
return SSHTerminalTab(windowScope, host)
}
override suspend fun openPtyConnector(): PtyConnector { override suspend fun openPtyConnector(): PtyConnector {
if (mutex.tryLock()) { if (mutex.tryLock()) {
try { try {
@@ -211,17 +215,6 @@ class SSHTerminalTab(
return super.getData(dataKey) return super.getData(dataKey)
} }
override fun reconnect() {
stop()
// 重新连接时就等于重新打开了一个标签handler 重置
handler.client = null
handler.session = null
handler.client = null
start()
}
override fun stop() { override fun stop() {
if (mutex.tryLock()) { if (mutex.tryLock()) {
try { try {

View File

@@ -1,9 +1,6 @@
package app.termora.plugin.internal.telnet package app.termora.plugin.internal.telnet
import app.termora.Host import app.termora.*
import app.termora.ProxyType
import app.termora.PtyHostTerminalTab
import app.termora.WindowScope
import app.termora.terminal.ControlCharacters import app.termora.terminal.ControlCharacters
import app.termora.terminal.KeyEncoderImpl import app.termora.terminal.KeyEncoderImpl
import app.termora.terminal.PtyConnector import app.termora.terminal.PtyConnector
@@ -71,5 +68,9 @@ class TelnetTerminalTab(
return ptyConnectorFactory.decorate(TelnetStreamPtyConnector(telnet, telnet.charset, characterMode)) return ptyConnectorFactory.decorate(TelnetStreamPtyConnector(telnet, telnet.charset, characterMode))
} }
override fun createReconnectTerminalTab(): TerminalTab {
return TelnetTerminalTab(windowScope, host)
}
} }

View File

@@ -1,9 +1,6 @@
package app.termora.plugin.internal.wsl package app.termora.plugin.internal.wsl
import app.termora.Host import app.termora.*
import app.termora.PtyConnectorFactory
import app.termora.PtyHostTerminalTab
import app.termora.WindowScope
import app.termora.terminal.PtyConnector import app.termora.terminal.PtyConnector
import org.apache.commons.io.Charsets import org.apache.commons.io.Charsets
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
@@ -51,6 +48,10 @@ class WSLHostTerminalTab(windowScope: WindowScope, host: Host) : PtyHostTerminal
return ptyConnector return ptyConnector
} }
override fun createReconnectTerminalTab(): TerminalTab {
return WSLHostTerminalTab(windowScope, host)
}
override fun sendStartupCommand(ptyConnector: PtyConnector, bytes: ByteArray) { override fun sendStartupCommand(ptyConnector: PtyConnector, bytes: ByteArray) {
// Nothing // Nothing

View File

@@ -1,9 +1,6 @@
package app.termora.tlog package app.termora.tlog
import app.termora.Host import app.termora.*
import app.termora.Icons
import app.termora.PtyHostTerminalTab
import app.termora.WindowScope
import app.termora.terminal.PtyConnector import app.termora.terminal.PtyConnector
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -71,6 +68,10 @@ class LogViewerTerminalTab(
return false return false
} }
override fun createReconnectTerminalTab(): TerminalTab {
throw UnsupportedOperationException()
}
override fun canClone(): Boolean { override fun canClone(): Boolean {
return false return false
} }