feat: support fast reconnect

This commit is contained in:
hstyi
2025-01-15 23:00:39 +08:00
committed by hstyi
parent 0884486e91
commit 0cd818e9a0
11 changed files with 96 additions and 34 deletions

View File

@@ -1,7 +1,10 @@
package app.termora
import app.termora.actions.TabReconnectAction
import app.termora.addons.zmodem.ZModemPtyConnectorAdaptor
import app.termora.keyboardinteractive.TerminalUserInteraction
import app.termora.keymap.KeyShortcut
import app.termora.keymap.KeymapManager
import app.termora.terminal.ControlCharacters
import app.termora.terminal.DataKey
import app.termora.terminal.PtyConnector
@@ -109,10 +112,18 @@ class SSHTerminalTab(windowScope: WindowScope, host: Host) : PtyHostTerminalTab(
channel.addChannelListener(object : ChannelListener {
private val reconnectShortcut
get() = KeymapManager.getInstance().getActiveKeymap()
.getShortcut(TabReconnectAction.RECONNECT_TAB).firstOrNull()
override fun channelClosed(channel: Channel, reason: Throwable?) {
coroutineScope.launch(Dispatchers.Swing) {
terminal.write("\r\n${ControlCharacters.ESC}[31m")
terminal.write("Channel has been disconnected.\r\n")
terminal.write("\r\n\r\n${ControlCharacters.ESC}[31m")
terminal.write("Channel has been disconnected.")
if (reconnectShortcut is KeyShortcut) {
terminal.write(" Type $reconnectShortcut to reconnect.")
}
terminal.write("\r\n")
terminal.write("${ControlCharacters.ESC}[0m")
terminalModel.setData(DataKey.ShowCursor, false)
}

View File

@@ -48,6 +48,8 @@ class TerminalTabDialog(
dataProviderSupport.addData(DataProviders.WindowScope, it)
}
}
dataProviderSupport.addData(DataProviders.TerminalTab, terminalTab)
}
override fun createSouthPanel(): JComponent? {

View File

@@ -181,16 +181,6 @@ class TerminalTabbed(
}
}
private fun openHost(host: Host) {
val tab = if (host.protocol == Protocol.SSH)
SSHTerminalTab(ApplicationScope.forWindowScope(this), host)
else LocalTerminalTab(ApplicationScope.forWindowScope(this), host)
addTab(tab)
tab.start()
}
private fun showContextMenu(tabIndex: Int, e: MouseEvent) {
val c = tabbedPane.getComponentAt(tabIndex) as JComponent
val tab = tabs[tabIndex]
@@ -438,6 +428,12 @@ class TerminalTabbed(
}
override fun <T : Any> getData(dataKey: DataKey<T>): T? {
if (dataKey == DataProviders.TerminalTab) {
dataProviderSupport.removeData(dataKey)
if (tabbedPane.selectedIndex >= 0 && tabs.size > tabbedPane.selectedIndex) {
dataProviderSupport.addData(dataKey, tabs[tabbedPane.selectedIndex])
}
}
return dataProviderSupport.getData(dataKey)
}

View File

@@ -228,6 +228,18 @@ class WelcomePanel(private val windowScope: WindowScope) : JPanel(BorderLayout()
return this
}
override fun canReconnect(): Boolean {
return false
}
override fun canClose(): Boolean {
return false
}
override fun canClone(): Boolean {
return false
}
override fun dispose() {
hostTree.setModel(null)
properties.putString("WelcomeFullContent", fullContent.toString())

View File

@@ -37,6 +37,7 @@ class ActionManager : org.jdesktop.swingx.action.ActionManager() {
addAction(Actions.KEY_MANAGER, KeyManagerAction())
addAction(SwitchTabAction.SWITCH_TAB, SwitchTabAction())
addAction(TabReconnectAction.RECONNECT_TAB, TabReconnectAction())
addAction(SettingsAction.SETTING, SettingsAction())
addAction(NewHostAction.NEW_HOST, NewHostAction())

View File

@@ -6,8 +6,11 @@ object DataProviders {
val TerminalPanel = DataKey(app.termora.terminal.panel.TerminalPanel::class)
val Terminal = DataKey(app.termora.terminal.Terminal::class)
val PtyConnector = DataKey(app.termora.terminal.PtyConnector::class)
val TerminalTabbed = DataKey(app.termora.TerminalTabbed::class)
val TerminalTab = DataKey(app.termora.TerminalTab::class)
val TerminalTabbedManager = DataKey(app.termora.TerminalTabbedManager::class)
val TermoraFrame = DataKey(app.termora.TermoraFrame::class)
val WindowScope = DataKey(app.termora.WindowScope::class)

View File

@@ -0,0 +1,21 @@
package app.termora.actions
import app.termora.I18n
class TabReconnectAction : AnAction() {
companion object {
const val RECONNECT_TAB = "TabReconnectAction"
}
init {
putValue(ACTION_COMMAND_KEY, RECONNECT_TAB)
putValue(SHORT_DESCRIPTION, I18n.getString("termora.tabbed.contextmenu.reconnect"))
}
override fun actionPerformed(evt: AnActionEvent) {
val tab = evt.getData(DataProviders.TerminalTab) ?: return
if (tab.canReconnect()) {
tab.reconnect()
}
}
}

View File

@@ -1,8 +1,32 @@
package app.termora.keymap
import org.apache.commons.lang3.StringUtils
import java.awt.event.KeyEvent
import javax.swing.KeyStroke
class KeyShortcut(val keyStroke: KeyStroke) : Shortcut() {
companion object {
fun toHumanText(keyStroke: KeyStroke): String {
var text = keyStroke.toString()
text = text.replace("shift", "")
text = text.replace("ctrl", "")
text = text.replace("meta", "")
text = text.replace("alt", "")
text = text.replace("pressed", StringUtils.EMPTY)
text = text.replace(StringUtils.SPACE, StringUtils.EMPTY)
if (keyStroke.keyCode == KeyEvent.VK_EQUALS) {
text = text.replace("EQUALS", "+")
} else if (keyStroke.keyCode == KeyEvent.VK_MINUS) {
text = text.replace("MINUS", "-")
}
return text.toCharArray().joinToString(" + ")
}
}
override fun isKeyboard(): Boolean {
return true
}
@@ -19,4 +43,8 @@ class KeyShortcut(val keyStroke: KeyStroke) : Shortcut() {
override fun hashCode(): Int {
return keyStroke.hashCode()
}
override fun toString(): String {
return toHumanText(keyStroke)
}
}

View File

@@ -70,6 +70,12 @@ class KeymapImpl(private val menuShortcutKeyMaskEx: Int) : Keymap("Keymap", null
KeyShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_0, menuShortcutKeyMaskEx))
)
// Command + Shift + R
addShortcut(
TabReconnectAction.RECONNECT_TAB,
KeyShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_R, menuShortcutKeyMaskEx or InputEvent.SHIFT_DOWN_MASK))
)
// switch map
for (i in KeyEvent.VK_1..KeyEvent.VK_9) {

View File

@@ -3,6 +3,7 @@ package app.termora.keymap
import app.termora.*
import app.termora.actions.ActionManager
import app.termora.actions.SwitchTabAction
import app.termora.keymap.KeyShortcut.Companion.toHumanText
import com.formdev.flatlaf.FlatClientProperties
import com.formdev.flatlaf.extras.components.FlatToolBar
import java.awt.BorderLayout
@@ -225,7 +226,7 @@ class KeymapPanel : JPanel(BorderLayout()) {
val text = duplicateAction.getValue(Action.SHORT_DESCRIPTION) ?: continue
OptionPane.showMessageDialog(
SwingUtilities.getWindowAncestor(this@KeymapPanel),
I18n.getString("termora.settings.keymap.already-exists", model.toHumanText(keyStroke), text),
I18n.getString("termora.settings.keymap.already-exists", toHumanText(keyStroke), text),
messageType = JOptionPane.ERROR_MESSAGE,
)
}

View File

@@ -3,12 +3,11 @@ package app.termora.keymap
import app.termora.I18n
import app.termora.actions.*
import app.termora.findeverywhere.FindEverywhereAction
import app.termora.keymap.KeyShortcut.Companion.toHumanText
import org.apache.commons.lang3.StringUtils
import org.jdesktop.swingx.action.ActionManager
import org.jdesktop.swingx.action.BoundAction.ACTION_COMMAND_KEY
import java.awt.event.KeyEvent
import javax.swing.Action
import javax.swing.KeyStroke
import javax.swing.table.DefaultTableModel
class KeymapTableModel : DefaultTableModel() {
@@ -30,6 +29,7 @@ class KeymapTableModel : DefaultTableModel() {
OpenLocalTerminalAction.LOCAL_TERMINAL,
FindEverywhereAction.FIND_EVERYWHERE,
NewWindowAction.NEW_WINDOW,
TabReconnectAction.RECONNECT_TAB,
SwitchTabAction.SWITCH_TAB,
)) {
val action = actionManager.getAction(id) ?: continue
@@ -75,24 +75,5 @@ class KeymapTableModel : DefaultTableModel() {
return false
}
fun toHumanText(keyStroke: KeyStroke): String {
var text = keyStroke.toString()
text = text.replace("shift", "")
text = text.replace("ctrl", "")
text = text.replace("meta", "")
text = text.replace("alt", "")
text = text.replace("pressed", StringUtils.EMPTY)
text = text.replace(StringUtils.SPACE, StringUtils.EMPTY)
if (keyStroke.keyCode == KeyEvent.VK_EQUALS) {
text = text.replace("EQUALS", "+")
} else if (keyStroke.keyCode == KeyEvent.VK_MINUS) {
text = text.replace("MINUS", "-")
}
return text.toCharArray().joinToString(" + ")
}
}