mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: support fast reconnect
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ class TerminalTabDialog(
|
||||
dataProviderSupport.addData(DataProviders.WindowScope, it)
|
||||
}
|
||||
}
|
||||
|
||||
dataProviderSupport.addData(DataProviders.TerminalTab, terminalTab)
|
||||
}
|
||||
|
||||
override fun createSouthPanel(): JComponent? {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
21
src/main/kotlin/app/termora/actions/TabReconnectAction.kt
Normal file
21
src/main/kotlin/app/termora/actions/TabReconnectAction.kt
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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(" + ")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user