From ae7730fb355dd7e82d6878acb5353b495f4ab52c Mon Sep 17 00:00:00 2001 From: hstyi Date: Fri, 18 Jul 2025 21:47:57 +0800 Subject: [PATCH] feat: keyword highlight set --- plugins/serial/build.gradle.kts | 2 +- .../plugins/serial/SerialHostOptionsPane.kt | 18 +- .../plugins/serial/SerialProtocolHostPanel.kt | 5 +- .../SerialProtocolHostPanelExtension.kt | 2 +- .../app/termora/highlight/KeywordHighlight.kt | 10 + .../KeywordHighlightPaintListener.kt | 24 +- .../highlight/KeywordHighlightPanel.kt | 607 +++++++++++------- .../highlight/KeywordHighlightTableModel.kt | 10 +- .../termora/highlight/KeywordHighlightType.kt | 6 + .../plugin/internal/BasicTerminalOption.kt | 45 +- .../internal/local/LocalHostOptionsPane.kt | 17 +- .../internal/local/LocalProtocolHostPanel.kt | 5 +- .../local/LocalProtocolHostPanelExtension.kt | 2 +- .../plugin/internal/ssh/SSHHostOptionsPane.kt | 16 + .../internal/telnet/TelnetHostOptionsPane.kt | 16 +- .../plugin/internal/wsl/WSLHostOptionsPane.kt | 15 + src/main/resources/i18n/messages.properties | 1 + .../resources/i18n/messages_ru_RU.properties | 1 + .../resources/i18n/messages_zh_CN.properties | 1 + .../resources/i18n/messages_zh_TW.properties | 1 + 20 files changed, 545 insertions(+), 259 deletions(-) create mode 100644 src/main/kotlin/app/termora/highlight/KeywordHighlightType.kt diff --git a/plugins/serial/build.gradle.kts b/plugins/serial/build.gradle.kts index 2241604..ec3fb64 100644 --- a/plugins/serial/build.gradle.kts +++ b/plugins/serial/build.gradle.kts @@ -4,7 +4,7 @@ plugins { -project.version = "0.0.3" +project.version = "0.0.4" dependencies { diff --git a/plugins/serial/src/main/kotlin/app/termora/plugins/serial/SerialHostOptionsPane.kt b/plugins/serial/src/main/kotlin/app/termora/plugins/serial/SerialHostOptionsPane.kt index 9be4985..13b0c25 100644 --- a/plugins/serial/src/main/kotlin/app/termora/plugins/serial/SerialHostOptionsPane.kt +++ b/plugins/serial/src/main/kotlin/app/termora/plugins/serial/SerialHostOptionsPane.kt @@ -1,6 +1,8 @@ package app.termora.plugins.serial import app.termora.* +import app.termora.account.AccountOwner +import app.termora.highlight.KeywordHighlight import app.termora.plugin.internal.AltKeyModifier import app.termora.plugin.internal.BasicGeneralOption import app.termora.plugin.internal.BasicTerminalOption @@ -19,11 +21,12 @@ import java.awt.event.ComponentAdapter import java.awt.event.ComponentEvent import javax.swing.* -class SerialHostOptionsPane : OptionsPane() { +class SerialHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPane() { private val generalOption = BasicGeneralOption() private val terminalOption = BasicTerminalOption().apply { showCharsetComboBox = true showStartupCommandTextField = true + accountOwner = this@SerialHostOptionsPane.accountOwner init() } private val serialCommOption = SerialCommOption() @@ -56,6 +59,8 @@ class SerialHostOptionsPane : OptionsPane() { extras = mutableMapOf( "altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString() ?: AltKeyModifier.EightBit.name), + "keywordHighlightSetId" to ((terminalOption.highlightSetComboBox.selectedItem as? KeywordHighlight)?.id + ?: "-1"), ) ) @@ -88,6 +93,17 @@ class SerialHostOptionsPane : OptionsPane() { val altModifier = host.options.extras["altModifier"] ?: AltKeyModifier.EightBit.name terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) } .getOrNull() ?: AltKeyModifier.EightBit + + + val keywordHighlightSetId = host.options.extras["keywordHighlightSetId"] + for (i in 0 until terminalOption.highlightSetComboBox.itemCount) { + val item = terminalOption.highlightSetComboBox.getItemAt(i) + if (item.id == keywordHighlightSetId) { + terminalOption.highlightSetComboBox.selectedItem = item + break + } + } + } fun validateFields(): Boolean { diff --git a/plugins/serial/src/main/kotlin/app/termora/plugins/serial/SerialProtocolHostPanel.kt b/plugins/serial/src/main/kotlin/app/termora/plugins/serial/SerialProtocolHostPanel.kt index c7094ae..9510a49 100644 --- a/plugins/serial/src/main/kotlin/app/termora/plugins/serial/SerialProtocolHostPanel.kt +++ b/plugins/serial/src/main/kotlin/app/termora/plugins/serial/SerialProtocolHostPanel.kt @@ -2,11 +2,12 @@ package app.termora.plugins.serial import app.termora.Disposer import app.termora.Host +import app.termora.account.AccountOwner import app.termora.protocol.ProtocolHostPanel import java.awt.BorderLayout -class SerialProtocolHostPanel : ProtocolHostPanel() { - private val pane = SerialHostOptionsPane() +class SerialProtocolHostPanel(accountOwner: AccountOwner) : ProtocolHostPanel() { + private val pane = SerialHostOptionsPane(accountOwner) init { initView() diff --git a/plugins/serial/src/main/kotlin/app/termora/plugins/serial/SerialProtocolHostPanelExtension.kt b/plugins/serial/src/main/kotlin/app/termora/plugins/serial/SerialProtocolHostPanelExtension.kt index d582374..7cf566a 100644 --- a/plugins/serial/src/main/kotlin/app/termora/plugins/serial/SerialProtocolHostPanelExtension.kt +++ b/plugins/serial/src/main/kotlin/app/termora/plugins/serial/SerialProtocolHostPanelExtension.kt @@ -16,7 +16,7 @@ internal class SerialProtocolHostPanelExtension private constructor() : Protocol } override fun createProtocolHostPanel(accountOwner: AccountOwner): ProtocolHostPanel { - return SerialProtocolHostPanel() + return SerialProtocolHostPanel(accountOwner) } override fun ordered(): Long { diff --git a/src/main/kotlin/app/termora/highlight/KeywordHighlight.kt b/src/main/kotlin/app/termora/highlight/KeywordHighlight.kt index 16fc233..c682695 100644 --- a/src/main/kotlin/app/termora/highlight/KeywordHighlight.kt +++ b/src/main/kotlin/app/termora/highlight/KeywordHighlight.kt @@ -8,6 +8,16 @@ import org.apache.commons.lang3.StringUtils data class KeywordHighlight( val id: String = randomUUID(), + /** + * Set id,默认 0 + */ + val parentId: String = "0", + + /** + * [KeywordHighlightType] + */ + val type: KeywordHighlightType = KeywordHighlightType.Highlight, + /** * 关键词 */ diff --git a/src/main/kotlin/app/termora/highlight/KeywordHighlightPaintListener.kt b/src/main/kotlin/app/termora/highlight/KeywordHighlightPaintListener.kt index cbe9d9d..eb28e6f 100644 --- a/src/main/kotlin/app/termora/highlight/KeywordHighlightPaintListener.kt +++ b/src/main/kotlin/app/termora/highlight/KeywordHighlightPaintListener.kt @@ -1,12 +1,9 @@ package app.termora.highlight -import app.termora.ApplicationScope -import app.termora.Disposable -import app.termora.Disposer +import app.termora.* import app.termora.account.Account import app.termora.account.AccountExtension import app.termora.account.AccountManager -import app.termora.assertEventDispatchThread import app.termora.database.DataType import app.termora.database.DatabaseChangedExtension import app.termora.plugin.internal.extension.DynamicExtensionHandler @@ -20,7 +17,7 @@ import java.util.concurrent.atomic.AtomicBoolean import kotlin.math.min import kotlin.random.Random -class KeywordHighlightPaintListener private constructor() : TerminalPaintListener, Disposable { +internal class KeywordHighlightPaintListener private constructor() : TerminalPaintListener, Disposable { companion object { fun getInstance(): KeywordHighlightPaintListener { @@ -93,10 +90,21 @@ class KeywordHighlightPaintListener private constructor() : TerminalPaintListene } } + // 默认情况是:默认集 + var keywordHighlightSetId = "0" + val terminalModel = terminal.getTerminalModel() + if (terminalModel.hasData(HostTerminalTab.Host)) { + val host = terminalModel.getData(HostTerminalTab.Host) + keywordHighlightSetId = host.options.extras["keywordHighlightSetId"] ?: keywordHighlightSetId + } + + // -1 表示不使用高亮集 + if (keywordHighlightSetId == "-1") return + for (highlight in keywordHighlights) { - if (highlight.enabled.not()) { - continue - } + if (highlight.enabled.not()) continue + if (highlight.type != KeywordHighlightType.Highlight) continue + if (keywordHighlightSetId != highlight.parentId) continue val document = terminal.getDocument() val kinds = mutableListOf() diff --git a/src/main/kotlin/app/termora/highlight/KeywordHighlightPanel.kt b/src/main/kotlin/app/termora/highlight/KeywordHighlightPanel.kt index 19cf735..446758f 100644 --- a/src/main/kotlin/app/termora/highlight/KeywordHighlightPanel.kt +++ b/src/main/kotlin/app/termora/highlight/KeywordHighlightPanel.kt @@ -4,6 +4,8 @@ import app.termora.* import app.termora.Application.ohMyJson import app.termora.account.AccountOwner import app.termora.terminal.TerminalColor +import com.formdev.flatlaf.extras.components.FlatPopupMenu +import com.formdev.flatlaf.extras.components.FlatTabbedPane import com.formdev.flatlaf.extras.components.FlatTable import com.jgoodies.forms.builder.FormBuilder import com.jgoodies.forms.layout.FormLayout @@ -12,12 +14,13 @@ import org.apache.commons.lang3.exception.ExceptionUtils import java.awt.BorderLayout import java.awt.Color import java.awt.Component +import java.awt.event.ActionEvent import java.awt.event.MouseAdapter import java.awt.event.MouseEvent import java.io.File import java.nio.charset.StandardCharsets import javax.swing.* -import javax.swing.border.EmptyBorder +import javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT import javax.swing.table.DefaultTableCellRenderer import javax.swing.table.TableCellRenderer @@ -25,17 +28,11 @@ import javax.swing.table.TableCellRenderer class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(BorderLayout()), Disposable { private val owner get() = SwingUtilities.getWindowAncestor(this) - private val model = KeywordHighlightTableModel(accountOwner) - private val table = FlatTable() private val keywordHighlightManager get() = KeywordHighlightManager.getInstance() private val terminal = TerminalFactory.getInstance().createTerminal() private val colorPalette get() = terminal.getTerminalModel().getColorPalette() - private val addBtn = JButton(I18n.getString("termora.new-host.tunneling.add")) - private val editBtn = JButton(I18n.getString("termora.keymgr.edit")) - private val deleteBtn = JButton(I18n.getString("termora.remove")) - private val importBtn = JButton(I18n.getString("termora.keymgr.import")) - private val exportBtn = JButton(I18n.getString("termora.keymgr.export")) + private val tabbed = FlatTabbedPane() init { initView() @@ -43,205 +40,50 @@ class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(Bor } private fun initView() { - model.addColumn(I18n.getString("termora.highlight.keyword")) - model.addColumn(I18n.getString("termora.highlight.preview")) - model.addColumn(I18n.getString("termora.highlight.description")) - table.fillsViewportHeight = true - table.tableHeader.reorderingAllowed = false - table.model = model - editBtn.isEnabled = false - deleteBtn.isEnabled = false + tabbed.styleMap = mapOf( + "focusColor" to DynamicColor("TabbedPane.background"), + "hoverColor" to DynamicColor("TabbedPane.background"), + "inactiveUnderlineColor" to DynamicColor("TabbedPane.underlineColor"), + ) + tabbed.isHasFullBorder = false + tabbed.tabPlacement = JTabbedPane.LEFT + tabbed.tabType = FlatTabbedPane.TabType.underlined + tabbed.isTabsClosable = false + tabbed.tabLayoutPolicy = SCROLL_TAB_LAYOUT + tabbed.tabWidthMode = FlatTabbedPane.TabWidthMode.preferred + tabbed.isFocusable = false + tabbed.tabHeight = UIManager.getInt("TabbedPane.tabHeight") - 8 - // keyword - table.columnModel.getColumn(0).setCellRenderer(object : JCheckBox(), TableCellRenderer { - init { - horizontalAlignment = LEFT - verticalAlignment = CENTER - } + val sets = keywordHighlightManager.getKeywordHighlights(accountOwner.id) + .filter { it.type == KeywordHighlightType.Set } + .sortedBy { it.sort } - override fun getTableCellRendererComponent( - table: JTable, - value: Any?, - isSelected: Boolean, - hasFocus: Boolean, - row: Int, - column: Int - ): Component { - if (value is KeywordHighlight) { - text = value.keyword - super.setSelected(value.enabled) - } - if (isSelected) { - foreground = table.selectionForeground - super.setBackground(table.selectionBackground) - } else { - foreground = table.foreground - background = table.background - } - return this - } + tabbed.addTab(I18n.getString("termora.highlight.default-set"), KeywordHighlightMiniPanel("0")) - }) - - // preview - table.columnModel.getColumn(1).setCellRenderer(object : DefaultTableCellRenderer() { - private val keywordHighlightView = KeywordHighlightView(0) - - init { - keywordHighlightView.border = null - } - - override fun getTableCellRendererComponent( - table: JTable, - value: Any?, - isSelected: Boolean, - hasFocus: Boolean, - row: Int, - column: Int - ): Component { - if (value is KeywordHighlight) { - keywordHighlightView.setKeywordHighlight(value, colorPalette) - if (isSelected) keywordHighlightView.backgroundColor = table.selectionBackground - return keywordHighlightView - } - return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column) - } - }) - - add(createCenterPanel(), BorderLayout.CENTER) + for (highlight in sets) { + tabbed.addTab(highlight.keyword, KeywordHighlightMiniPanel(highlight.id)) + } + add(tabbed, BorderLayout.CENTER) } private fun initEvents() { - table.addMouseListener(object : MouseAdapter() { + tabbed.addMouseListener(object : MouseAdapter() { override fun mouseClicked(e: MouseEvent) { - if (SwingUtilities.isLeftMouseButton(e)) { - val row = table.rowAtPoint(e.point) - val column = table.columnAtPoint(e.point) - if (row >= 0 && column == 0) { - val keywordHighlight = model.getKeywordHighlight(row) - keywordHighlightManager.addKeywordHighlight( - keywordHighlight.copy(enabled = !keywordHighlight.enabled), - accountOwner - ) - model.fireTableCellUpdated(row, column) - } + if (SwingUtilities.isRightMouseButton(e).not()) { + return } + + val index = tabbed.indexAtLocation(e.x, e.y) + if (index < 0) return + tabbed.selectedIndex = index + + showContextmenu(index, e) } }) - addBtn.addActionListener { - val dialog = NewKeywordHighlightDialog(owner, colorPalette) - dialog.setLocationRelativeTo(owner) - dialog.isVisible = true - val keywordHighlight = dialog.keywordHighlight - if (keywordHighlight != null) { - keywordHighlightManager.addKeywordHighlight(keywordHighlight, accountOwner) - model.fireTableRowsInserted(model.rowCount - 1, model.rowCount) - } - } - - editBtn.addActionListener { - val row = table.selectedRow - if (row > -1) { - var keywordHighlight = model.getKeywordHighlight(row) - val dialog = NewKeywordHighlightDialog(owner, colorPalette) - dialog.setLocationRelativeTo(owner) - dialog.keywordTextField.text = keywordHighlight.keyword - dialog.descriptionTextField.text = keywordHighlight.description - - if (keywordHighlight.textColor <= 16) { - if (keywordHighlight.textColor == 0) { - dialog.textColor.color = Color(colorPalette.getColor(TerminalColor.Basic.FOREGROUND)) - } else { - dialog.textColor.color = Color(colorPalette.getXTerm256Color(keywordHighlight.textColor)) - } - dialog.textColor.colorIndex = keywordHighlight.textColor - } else { - dialog.textColor.color = Color(keywordHighlight.textColor) - dialog.textColor.colorIndex = -1 - } - - if (keywordHighlight.backgroundColor <= 16) { - if (keywordHighlight.backgroundColor == 0) { - dialog.backgroundColor.color = Color(colorPalette.getColor(TerminalColor.Basic.BACKGROUND)) - } else { - dialog.backgroundColor.color = - Color(colorPalette.getXTerm256Color(keywordHighlight.backgroundColor)) - } - dialog.backgroundColor.colorIndex = keywordHighlight.backgroundColor - } else { - dialog.backgroundColor.color = Color(keywordHighlight.backgroundColor) - dialog.backgroundColor.colorIndex = -1 - } - - dialog.boldCheckBox.isSelected = keywordHighlight.bold - dialog.italicCheckBox.isSelected = keywordHighlight.italic - dialog.underlineCheckBox.isSelected = keywordHighlight.underline - dialog.lineThroughCheckBox.isSelected = keywordHighlight.lineThrough - dialog.matchCaseBtn.isSelected = keywordHighlight.matchCase - dialog.regexBtn.isSelected = keywordHighlight.regex - - dialog.isVisible = true - - val value = dialog.keywordHighlight - if (value != null) { - keywordHighlight = value.copy(id = keywordHighlight.id, sort = keywordHighlight.sort) - keywordHighlightManager.addKeywordHighlight(keywordHighlight, accountOwner) - model.fireTableRowsUpdated(row, row) - } - } - - } - - deleteBtn.addActionListener { - if (table.selectedRowCount > 0) { - if (OptionPane.showConfirmDialog( - SwingUtilities.getWindowAncestor(this), - I18n.getString("termora.keymgr.delete-warning"), - messageType = JOptionPane.WARNING_MESSAGE - ) == JOptionPane.YES_OPTION - ) { - val rows = table.selectedRows.sorted().reversed() - for (row in rows) { - val id = model.getKeywordHighlight(row).id - keywordHighlightManager.removeKeywordHighlight(id) - model.fireTableRowsDeleted(row, row) - } - } - } - } - - table.selectionModel.addListSelectionListener { - editBtn.isEnabled = table.selectedRowCount > 0 - deleteBtn.isEnabled = editBtn.isEnabled - } - - exportBtn.addActionListener { - val fileChooser = FileChooser() - fileChooser.fileSelectionMode = JFileChooser.FILES_ONLY - fileChooser.win32Filters.add(Pair("All files", listOf("*"))) - fileChooser.showSaveDialog(owner, "highlights.json").thenAccept { file -> - file?.outputStream()?.use { - val highlights = keywordHighlightManager.getKeywordHighlights(accountOwner.id) - .map { e -> e.copy(id = randomUUID()) } - IOUtils.write(ohMyJson.encodeToString(highlights), it, StandardCharsets.UTF_8) - } - } - } - - importBtn.addActionListener { - val chooser = FileChooser() - chooser.osxAllowedFileTypes = listOf("json") - chooser.allowsMultiSelection = false - chooser.win32Filters.add(Pair("JSON files", listOf("json"))) - chooser.fileSelectionMode = JFileChooser.FILES_ONLY - chooser.showOpenDialog(owner) - .thenAccept { if (it.isNotEmpty()) SwingUtilities.invokeLater { importKeywordHighlights(it.first()) } } - } - Disposer.register(this, object : Disposable { override fun dispose() { terminal.close() @@ -249,54 +91,343 @@ class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(Bor }) } - private fun importKeywordHighlights(file: File) { - try { - val highlights = ohMyJson.decodeFromString>(file.readText()) - .map { it.copy(id = randomUUID()) } - for (highlight in highlights) { + private fun showContextmenu(index: Int, e: MouseEvent) { + + var offset = 0 + for (i in 0..index) offset += tabbed.ui.getTabBounds(tabbed, i).height + val popupMenu = FlatPopupMenu() + popupMenu.add(I18n.getString("termora.new-host.tunneling.add")).addActionListener(object : AbstractAction() { + override fun actionPerformed(e: ActionEvent) { + val text = OptionPane.showInputDialog(owner) ?: return + if (text.isBlank()) return + val highlight = KeywordHighlight( + keyword = text, + type = KeywordHighlightType.Set + ) keywordHighlightManager.addKeywordHighlight(highlight, accountOwner) - model.fireTableRowsInserted(model.rowCount - 1, model.rowCount) + tabbed.addTab(text, KeywordHighlightMiniPanel(highlight.id)) + tabbed.selectedIndex = tabbed.tabCount - 1 } - } catch (e: Exception) { - OptionPane.showMessageDialog( - owner, - message = e.message ?: ExceptionUtils.getRootCauseMessage(e), - messageType = JOptionPane.ERROR_MESSAGE, + }) + + if (index > 0) { + popupMenu.add(I18n.getString("termora.tabbed.contextmenu.rename")) + .addActionListener(object : AbstractAction() { + override fun actionPerformed(e: ActionEvent) { + val tab = tabbed.getComponentAt(index) as? KeywordHighlightMiniPanel ?: return + val title = tabbed.getTitleAt(index) ?: return + val text = OptionPane.showInputDialog(owner, value = title) ?: return + if (text.isBlank() || title == text) return + val highlight = keywordHighlightManager.getKeywordHighlights(accountOwner.id) + .filter { it.type == KeywordHighlightType.Set } + .firstOrNull { it.id == tab.setId } ?: return + keywordHighlightManager.addKeywordHighlight( + highlight.copy( + updateDate = System.currentTimeMillis(), + keyword = text + ), accountOwner + ) + tabbed.setTitleAt(index, text) + } + }) + + popupMenu.add(I18n.getString("termora.remove")).addActionListener(object : AbstractAction() { + override fun actionPerformed(e: ActionEvent) { + val tab = tabbed.getComponentAt(index) as? KeywordHighlightMiniPanel ?: return + + if (OptionPane.showConfirmDialog( + owner, + I18n.getString("termora.keymgr.delete-warning"), + I18n.getString("termora.remove"), + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE + ) != JOptionPane.YES_OPTION + ) return + + tabbed.removeTabAt(index) + + for (highlight in keywordHighlightManager.getKeywordHighlights(accountOwner.id)) { + if (highlight.parentId == tab.setId || highlight.id == tab.setId) { + keywordHighlightManager.removeKeywordHighlight(highlight.id) + } + } + } + }) + } + + popupMenu.show(e.component, e.x, e.y) + } + + + private inner class KeywordHighlightMiniPanel(val setId: String) : JPanel(BorderLayout()) { + + private val addBtn = JButton(I18n.getString("termora.new-host.tunneling.add")) + private val editBtn = JButton(I18n.getString("termora.keymgr.edit")) + private val deleteBtn = JButton(I18n.getString("termora.remove")) + private val importBtn = JButton(I18n.getString("termora.keymgr.import")) + private val exportBtn = JButton(I18n.getString("termora.keymgr.export")) + private val model = KeywordHighlightTableModel(accountOwner, setId) + private val table = FlatTable() + + init { + initView() + initEvents() + } + + private fun initView() { + model.addColumn(I18n.getString("termora.highlight.keyword")) + model.addColumn(I18n.getString("termora.highlight.preview")) + model.addColumn(I18n.getString("termora.highlight.description")) + table.fillsViewportHeight = true + table.tableHeader.reorderingAllowed = false + table.model = model + + editBtn.isEnabled = false + deleteBtn.isEnabled = false + + // keyword + table.columnModel.getColumn(0).setCellRenderer(object : JCheckBox(), TableCellRenderer { + init { + horizontalAlignment = LEFT + verticalAlignment = CENTER + } + + override fun getTableCellRendererComponent( + table: JTable, + value: Any?, + isSelected: Boolean, + hasFocus: Boolean, + row: Int, + column: Int + ): Component { + if (value is KeywordHighlight) { + text = value.keyword + super.setSelected(value.enabled) + } + if (isSelected) { + foreground = table.selectionForeground + super.setBackground(table.selectionBackground) + } else { + foreground = table.foreground + background = table.background + } + return this + } + + }) + + // preview + table.columnModel.getColumn(1).setCellRenderer(object : DefaultTableCellRenderer() { + private val keywordHighlightView = KeywordHighlightView(0) + + init { + keywordHighlightView.border = null + } + + override fun getTableCellRendererComponent( + table: JTable, + value: Any?, + isSelected: Boolean, + hasFocus: Boolean, + row: Int, + column: Int + ): Component { + if (value is KeywordHighlight) { + keywordHighlightView.setKeywordHighlight(value, colorPalette) + if (isSelected) keywordHighlightView.backgroundColor = table.selectionBackground + return keywordHighlightView + } + return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column) + } + }) + + add(createCenterPanel(), BorderLayout.CENTER) + } + + private fun initEvents() { + + table.addMouseListener(object : MouseAdapter() { + override fun mouseClicked(e: MouseEvent) { + if (SwingUtilities.isLeftMouseButton(e)) { + val row = table.rowAtPoint(e.point) + val column = table.columnAtPoint(e.point) + if (row >= 0 && column == 0) { + val keywordHighlight = model.getKeywordHighlight(row) + keywordHighlightManager.addKeywordHighlight( + keywordHighlight.copy(enabled = keywordHighlight.enabled.not()), + accountOwner + ) + model.fireTableCellUpdated(row, column) + } else if (row < 0) { + table.clearSelection() + } + } + } + }) + + addBtn.addActionListener { + val dialog = NewKeywordHighlightDialog(owner, colorPalette) + dialog.setLocationRelativeTo(owner) + dialog.isVisible = true + val keywordHighlight = dialog.keywordHighlight + if (keywordHighlight != null) { + keywordHighlightManager.addKeywordHighlight(keywordHighlight.copy(parentId = setId), accountOwner) + model.fireTableRowsInserted(model.rowCount - 1, model.rowCount) + } + } + + editBtn.addActionListener { + val row = table.selectedRow + if (row > -1) { + var keywordHighlight = model.getKeywordHighlight(row) + val dialog = NewKeywordHighlightDialog(owner, colorPalette) + dialog.setLocationRelativeTo(owner) + dialog.keywordTextField.text = keywordHighlight.keyword + dialog.descriptionTextField.text = keywordHighlight.description + + if (keywordHighlight.textColor <= 16) { + if (keywordHighlight.textColor == 0) { + dialog.textColor.color = Color(colorPalette.getColor(TerminalColor.Basic.FOREGROUND)) + } else { + dialog.textColor.color = Color(colorPalette.getXTerm256Color(keywordHighlight.textColor)) + } + dialog.textColor.colorIndex = keywordHighlight.textColor + } else { + dialog.textColor.color = Color(keywordHighlight.textColor) + dialog.textColor.colorIndex = -1 + } + + if (keywordHighlight.backgroundColor <= 16) { + if (keywordHighlight.backgroundColor == 0) { + dialog.backgroundColor.color = Color(colorPalette.getColor(TerminalColor.Basic.BACKGROUND)) + } else { + dialog.backgroundColor.color = + Color(colorPalette.getXTerm256Color(keywordHighlight.backgroundColor)) + } + dialog.backgroundColor.colorIndex = keywordHighlight.backgroundColor + } else { + dialog.backgroundColor.color = Color(keywordHighlight.backgroundColor) + dialog.backgroundColor.colorIndex = -1 + } + + dialog.boldCheckBox.isSelected = keywordHighlight.bold + dialog.italicCheckBox.isSelected = keywordHighlight.italic + dialog.underlineCheckBox.isSelected = keywordHighlight.underline + dialog.lineThroughCheckBox.isSelected = keywordHighlight.lineThrough + dialog.matchCaseBtn.isSelected = keywordHighlight.matchCase + dialog.regexBtn.isSelected = keywordHighlight.regex + + dialog.isVisible = true + + val value = dialog.keywordHighlight + if (value != null) { + keywordHighlight = value.copy( + id = keywordHighlight.id, parentId = setId, + sort = keywordHighlight.sort + ) + keywordHighlightManager.addKeywordHighlight(keywordHighlight, accountOwner) + model.fireTableRowsUpdated(row, row) + } + } + + } + + deleteBtn.addActionListener { + if (table.selectedRowCount > 0) { + if (OptionPane.showConfirmDialog( + SwingUtilities.getWindowAncestor(this), + I18n.getString("termora.keymgr.delete-warning"), + messageType = JOptionPane.WARNING_MESSAGE + ) == JOptionPane.YES_OPTION + ) { + val rows = table.selectedRows.sorted().reversed() + for (row in rows) { + val id = model.getKeywordHighlight(row).id + keywordHighlightManager.removeKeywordHighlight(id) + model.fireTableRowsDeleted(row, row) + } + } + } + } + + table.selectionModel.addListSelectionListener { + editBtn.isEnabled = table.selectedRowCount > 0 + deleteBtn.isEnabled = editBtn.isEnabled + } + + exportBtn.addActionListener { + val fileChooser = FileChooser() + fileChooser.fileSelectionMode = JFileChooser.FILES_ONLY + fileChooser.win32Filters.add(Pair("All files", listOf("*"))) + fileChooser.showSaveDialog(owner, "highlights.json").thenAccept { file -> + file?.outputStream()?.use { + val highlights = keywordHighlightManager.getKeywordHighlights(accountOwner.id) + .filter { e -> e.parentId == setId } + .map { e -> e.copy(id = randomUUID()) } + IOUtils.write(ohMyJson.encodeToString(highlights), it, StandardCharsets.UTF_8) + } + } + } + + importBtn.addActionListener { + val chooser = FileChooser() + chooser.osxAllowedFileTypes = listOf("json") + chooser.allowsMultiSelection = false + chooser.win32Filters.add(Pair("JSON files", listOf("json"))) + chooser.fileSelectionMode = JFileChooser.FILES_ONLY + chooser.showOpenDialog(owner) + .thenAccept { if (it.isNotEmpty()) SwingUtilities.invokeLater { importKeywordHighlights(it.first()) } } + } + + } + + private fun importKeywordHighlights(file: File) { + try { + val highlights = ohMyJson.decodeFromString>(file.readText()) + .map { it.copy(id = randomUUID(), parentId = setId) } + for (highlight in highlights) { + keywordHighlightManager.addKeywordHighlight(highlight, accountOwner) + model.fireTableRowsInserted(model.rowCount - 1, model.rowCount) + } + } catch (e: Exception) { + OptionPane.showMessageDialog( + owner, + message = e.message ?: ExceptionUtils.getRootCauseMessage(e), + messageType = JOptionPane.ERROR_MESSAGE, + ) + } + } + + + private fun createCenterPanel(): JComponent { + + val panel = JPanel(BorderLayout()) + panel.add(JScrollPane(table).apply { + border = BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder(8, 8, 8, 0), + BorderFactory.createMatteBorder(1, 1, 1, 1, DynamicColor.BorderColor) + ) + }, BorderLayout.CENTER) + + var rows = 1 + val step = 2 + val formMargin = "4dlu" + val layout = FormLayout( + "default:grow", + "pref, $formMargin, pref, $formMargin, pref, $formMargin, pref, $formMargin, pref" ) + panel.add( + FormBuilder.create().layout(layout) + .border(BorderFactory.createEmptyBorder(8, 8, 8, 8)) + .add(addBtn).xy(1, rows).apply { rows += step } + .add(editBtn).xy(1, rows).apply { rows += step } + .add(deleteBtn).xy(1, rows).apply { rows += step } + .add(importBtn).xy(1, rows).apply { rows += step } + .add(exportBtn).xy(1, rows).apply { rows += step } + .build(), + BorderLayout.EAST) + + return panel } } - - private fun createCenterPanel(): JComponent { - - val panel = JPanel(BorderLayout()) - panel.add(JScrollPane(table).apply { - border = BorderFactory.createMatteBorder(1, 1, 1, 1, DynamicColor.BorderColor) - }, BorderLayout.CENTER) - - var rows = 1 - val step = 2 - val formMargin = "4dlu" - val layout = FormLayout( - "default:grow", - "pref, $formMargin, pref, $formMargin, pref, $formMargin, pref, $formMargin, pref" - ) - panel.add( - FormBuilder.create().layout(layout).padding(EmptyBorder(0, 12, 0, 0)) - .add(addBtn).xy(1, rows).apply { rows += step } - .add(editBtn).xy(1, rows).apply { rows += step } - .add(deleteBtn).xy(1, rows).apply { rows += step } - .add(importBtn).xy(1, rows).apply { rows += step } - .add(exportBtn).xy(1, rows).apply { rows += step } - .build(), - BorderLayout.EAST) - - panel.border = BorderFactory.createEmptyBorder( - 12, - 12, 12, 12 - ) - - return panel - } - - } \ No newline at end of file diff --git a/src/main/kotlin/app/termora/highlight/KeywordHighlightTableModel.kt b/src/main/kotlin/app/termora/highlight/KeywordHighlightTableModel.kt index 129c336..2bd727f 100644 --- a/src/main/kotlin/app/termora/highlight/KeywordHighlightTableModel.kt +++ b/src/main/kotlin/app/termora/highlight/KeywordHighlightTableModel.kt @@ -3,8 +3,14 @@ package app.termora.highlight import app.termora.account.AccountOwner import javax.swing.table.DefaultTableModel -class KeywordHighlightTableModel(private val accountOwner: AccountOwner) : DefaultTableModel() { - private val rows get() = KeywordHighlightManager.getInstance().getKeywordHighlights(accountOwner.id) +class KeywordHighlightTableModel( + private val accountOwner: AccountOwner, + private val setId: String +) : DefaultTableModel() { + private val rows + get() = KeywordHighlightManager.getInstance() + .getKeywordHighlights(accountOwner.id).filter { it.parentId == setId } + .filter { it.type == KeywordHighlightType.Highlight } override fun isCellEditable(row: Int, column: Int): Boolean { return false diff --git a/src/main/kotlin/app/termora/highlight/KeywordHighlightType.kt b/src/main/kotlin/app/termora/highlight/KeywordHighlightType.kt new file mode 100644 index 0000000..1ef3792 --- /dev/null +++ b/src/main/kotlin/app/termora/highlight/KeywordHighlightType.kt @@ -0,0 +1,6 @@ +package app.termora.highlight + +enum class KeywordHighlightType { + Set, + Highlight, +} \ No newline at end of file diff --git a/src/main/kotlin/app/termora/plugin/internal/BasicTerminalOption.kt b/src/main/kotlin/app/termora/plugin/internal/BasicTerminalOption.kt index 8455b25..d1d6114 100644 --- a/src/main/kotlin/app/termora/plugin/internal/BasicTerminalOption.kt +++ b/src/main/kotlin/app/termora/plugin/internal/BasicTerminalOption.kt @@ -3,6 +3,10 @@ package app.termora.plugin.internal import app.termora.* import app.termora.OptionsPane.Companion.FORM_MARGIN import app.termora.OptionsPane.Option +import app.termora.account.AccountOwner +import app.termora.highlight.KeywordHighlight +import app.termora.highlight.KeywordHighlightManager +import app.termora.highlight.KeywordHighlightType import app.termora.plugin.internal.telnet.TelnetHostOptionsPane.Backspace import com.formdev.flatlaf.extras.components.FlatTabbedPane import com.formdev.flatlaf.ui.FlatTextBorder @@ -24,6 +28,8 @@ class BasicTerminalOption() : JPanel(BorderLayout()), Option { var showBackspaceComboBox: Boolean = false var showCharacterAtATimeTextField: Boolean = false var showAltModifierComboBox: Boolean = true + var showHighlightSet: Boolean = true + var accountOwner: AccountOwner? = null val charsetComboBox = JComboBox() val startupCommandTextField = OutlineTextField() @@ -32,6 +38,7 @@ class BasicTerminalOption() : JPanel(BorderLayout()), Option { val loginScripts = mutableListOf() val backspaceComboBox = JComboBox() val altModifierComboBox = JComboBox() + val highlightSetComboBox = JComboBox() val characterAtATimeTextField = YesOrNoComboBox() @@ -82,6 +89,36 @@ class BasicTerminalOption() : JPanel(BorderLayout()), Option { } } + val accountOwner = this.accountOwner + if (showHighlightSet && accountOwner != null) { + val highlights = KeywordHighlightManager.getInstance() + .getKeywordHighlights(accountOwner.id) + .filter { it.type == KeywordHighlightType.Set } + highlightSetComboBox.addItem(KeywordHighlight(id = "-1", keyword = "None")) + val defaultHighlight = KeywordHighlight(id = "0", keyword = I18n.getString("termora.highlight.default-set")) + highlightSetComboBox.addItem(defaultHighlight) + for (highlight in highlights) { + highlightSetComboBox.addItem(highlight) + } + highlightSetComboBox.selectedItem = defaultHighlight + + highlightSetComboBox.renderer = object : DefaultListCellRenderer() { + override fun getListCellRendererComponent( + list: JList<*>?, + value: Any?, + index: Int, + isSelected: Boolean, + cellHasFocus: Boolean + ): Component? { + var text = value?.toString() ?: value + if (value is KeywordHighlight) { + text = value.keyword + } + return super.getListCellRendererComponent(list, text, index, isSelected, cellHasFocus) + } + } + } + if (showBackspaceComboBox) { backspaceComboBox.addItem(Backspace.Delete) @@ -136,9 +173,10 @@ class BasicTerminalOption() : JPanel(BorderLayout()), Option { private fun getCenterComponent(): JComponent { val layout = FormLayout( "left:pref, $FORM_MARGIN, default:grow", - "pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref" + "pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref" ) + val accountOwner = this.accountOwner var rows = 1 val step = 2 val builder = FormBuilder.create().layout(layout) @@ -151,6 +189,11 @@ class BasicTerminalOption() : JPanel(BorderLayout()), Option { .add(charsetComboBox).xy(3, rows).apply { rows += step } } + if (showHighlightSet && accountOwner != null) { + builder.add("${I18n.getString("termora.highlight")}:").xy(1, rows) + .add(highlightSetComboBox).xy(3, rows).apply { rows += step } + } + if (showAltModifierComboBox) { builder.add("${I18n.getString("termora.new-host.terminal.alt-modifier")}:").xy(1, rows) .add(altModifierComboBox).xy(3, rows).apply { rows += step } diff --git a/src/main/kotlin/app/termora/plugin/internal/local/LocalHostOptionsPane.kt b/src/main/kotlin/app/termora/plugin/internal/local/LocalHostOptionsPane.kt index b3cfc01..b993439 100644 --- a/src/main/kotlin/app/termora/plugin/internal/local/LocalHostOptionsPane.kt +++ b/src/main/kotlin/app/termora/plugin/internal/local/LocalHostOptionsPane.kt @@ -4,6 +4,8 @@ import app.termora.Host import app.termora.Options import app.termora.OptionsPane import app.termora.SerialComm +import app.termora.account.AccountOwner +import app.termora.highlight.KeywordHighlight import app.termora.plugin.internal.AltKeyModifier import app.termora.plugin.internal.BasicGeneralOption import app.termora.plugin.internal.BasicTerminalOption @@ -12,12 +14,14 @@ import java.awt.Window import javax.swing.JTextField import javax.swing.SwingUtilities -internal open class LocalHostOptionsPane : OptionsPane() { +internal open class LocalHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPane() { protected val generalOption = BasicGeneralOption() private val terminalOption = BasicTerminalOption().apply { showCharsetComboBox = true showEnvironmentTextArea = true showStartupCommandTextField = true + showHighlightSet = true + accountOwner = this@LocalHostOptionsPane.accountOwner init() } protected val owner: Window get() = SwingUtilities.getWindowAncestor(this) @@ -43,6 +47,8 @@ internal open class LocalHostOptionsPane : OptionsPane() { extras = mutableMapOf( "altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString() ?: AltKeyModifier.EightBit.name), + "keywordHighlightSetId" to ((terminalOption.highlightSetComboBox.selectedItem as? KeywordHighlight)?.id + ?: "-1"), ) ) @@ -66,6 +72,15 @@ internal open class LocalHostOptionsPane : OptionsPane() { val altModifier = host.options.extras["altModifier"] ?: AltKeyModifier.EightBit.name terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) } .getOrNull() ?: AltKeyModifier.EightBit + + val keywordHighlightSetId = host.options.extras["keywordHighlightSetId"] + for (i in 0 until terminalOption.highlightSetComboBox.itemCount) { + val item = terminalOption.highlightSetComboBox.getItemAt(i) + if (item.id == keywordHighlightSetId) { + terminalOption.highlightSetComboBox.selectedItem = item + break + } + } } fun validateFields(): Boolean { diff --git a/src/main/kotlin/app/termora/plugin/internal/local/LocalProtocolHostPanel.kt b/src/main/kotlin/app/termora/plugin/internal/local/LocalProtocolHostPanel.kt index d6ed1b0..b8e6c44 100644 --- a/src/main/kotlin/app/termora/plugin/internal/local/LocalProtocolHostPanel.kt +++ b/src/main/kotlin/app/termora/plugin/internal/local/LocalProtocolHostPanel.kt @@ -2,12 +2,13 @@ package app.termora.plugin.internal.local import app.termora.Disposer import app.termora.Host +import app.termora.account.AccountOwner import app.termora.protocol.ProtocolHostPanel import java.awt.BorderLayout -internal class LocalProtocolHostPanel : ProtocolHostPanel() { +internal class LocalProtocolHostPanel(accountOwner: AccountOwner) : ProtocolHostPanel() { - private val pane = LocalHostOptionsPane() + private val pane = LocalHostOptionsPane(accountOwner) init { initView() diff --git a/src/main/kotlin/app/termora/plugin/internal/local/LocalProtocolHostPanelExtension.kt b/src/main/kotlin/app/termora/plugin/internal/local/LocalProtocolHostPanelExtension.kt index 635d7d2..90777b4 100644 --- a/src/main/kotlin/app/termora/plugin/internal/local/LocalProtocolHostPanelExtension.kt +++ b/src/main/kotlin/app/termora/plugin/internal/local/LocalProtocolHostPanelExtension.kt @@ -16,7 +16,7 @@ internal class LocalProtocolHostPanelExtension private constructor() : ProtocolH } override fun createProtocolHostPanel(accountOwner: AccountOwner): ProtocolHostPanel { - return LocalProtocolHostPanel() + return LocalProtocolHostPanel(accountOwner) } override fun ordered(): Long { diff --git a/src/main/kotlin/app/termora/plugin/internal/ssh/SSHHostOptionsPane.kt b/src/main/kotlin/app/termora/plugin/internal/ssh/SSHHostOptionsPane.kt index 3e26c55..2d3e476 100644 --- a/src/main/kotlin/app/termora/plugin/internal/ssh/SSHHostOptionsPane.kt +++ b/src/main/kotlin/app/termora/plugin/internal/ssh/SSHHostOptionsPane.kt @@ -2,6 +2,7 @@ package app.termora.plugin.internal.ssh import app.termora.* import app.termora.account.AccountOwner +import app.termora.highlight.KeywordHighlight import app.termora.keymgr.KeyManager import app.termora.keymgr.KeyManagerDialog import app.termora.plugin.internal.AltKeyModifier @@ -37,6 +38,8 @@ internal class SSHHostOptionsPane(private val accountOwner: AccountOwner) : Opti showEnvironmentTextArea = true showStartupCommandTextField = true showHeartbeatIntervalTextField = true + showHighlightSet = true + accountOwner = this@SSHHostOptionsPane.accountOwner init() } private val jumpHostsOption = JumpHostsOption() @@ -108,6 +111,8 @@ internal class SSHHostOptionsPane(private val accountOwner: AccountOwner) : Opti extras = mutableMapOf( "altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString() ?: AltKeyModifier.EightBit.name), + "keywordHighlightSetId" to ((terminalOption.highlightSetComboBox.selectedItem as? KeywordHighlight)?.id + ?: "-1"), ) ) @@ -157,6 +162,17 @@ internal class SSHHostOptionsPane(private val accountOwner: AccountOwner) : Opti terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) } .getOrNull() ?: AltKeyModifier.EightBit + + val keywordHighlightSetId = host.options.extras["keywordHighlightSetId"] + for (i in 0 until terminalOption.highlightSetComboBox.itemCount) { + val item = terminalOption.highlightSetComboBox.getItemAt(i) + if (item.id == keywordHighlightSetId) { + terminalOption.highlightSetComboBox.selectedItem = item + break + } + } + + tunnelingOption.tunnelings.addAll(host.tunnelings) tunnelingOption.x11ForwardingCheckBox.isSelected = host.options.enableX11Forwarding tunnelingOption.x11ServerTextField.text = StringUtils.defaultIfBlank(host.options.x11Forwarding, "localhost:0") diff --git a/src/main/kotlin/app/termora/plugin/internal/telnet/TelnetHostOptionsPane.kt b/src/main/kotlin/app/termora/plugin/internal/telnet/TelnetHostOptionsPane.kt index 62fd9c3..1eccca6 100644 --- a/src/main/kotlin/app/termora/plugin/internal/telnet/TelnetHostOptionsPane.kt +++ b/src/main/kotlin/app/termora/plugin/internal/telnet/TelnetHostOptionsPane.kt @@ -2,6 +2,7 @@ package app.termora.plugin.internal.telnet import app.termora.* import app.termora.account.AccountOwner +import app.termora.highlight.KeywordHighlight import app.termora.plugin.internal.AltKeyModifier import app.termora.plugin.internal.BasicProxyOption import app.termora.plugin.internal.BasicTerminalOption @@ -16,7 +17,7 @@ import java.awt.event.ComponentEvent import javax.swing.* class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPane() { - protected val generalOption = GeneralOption() + private val generalOption = GeneralOption() // telnet 不支持代理密码 private val proxyOption = BasicProxyOption(authenticationTypes = listOf()) @@ -27,6 +28,7 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan showCharacterAtATimeTextField = true showEnvironmentTextArea = true showLoginScripts = true + accountOwner = this@TelnetHostOptionsPane.accountOwner init() } @@ -70,6 +72,8 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan "character-at-a-time" to (terminalOption.characterAtATimeTextField.selectedItem?.toString() ?: "false"), "altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString() ?: AltKeyModifier.EightBit.name), + "keywordHighlightSetId" to ((terminalOption.highlightSetComboBox.selectedItem as? KeywordHighlight)?.id + ?: "-1"), ) ) @@ -109,6 +113,16 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) } .getOrNull() ?: AltKeyModifier.EightBit + + val keywordHighlightSetId = host.options.extras["keywordHighlightSetId"] + for (i in 0 until terminalOption.highlightSetComboBox.itemCount) { + val item = terminalOption.highlightSetComboBox.getItemAt(i) + if (item.id == keywordHighlightSetId) { + terminalOption.highlightSetComboBox.selectedItem = item + break + } + } + terminalOption.loginScripts.clear() terminalOption.loginScripts.addAll(host.options.loginScripts) } diff --git a/src/main/kotlin/app/termora/plugin/internal/wsl/WSLHostOptionsPane.kt b/src/main/kotlin/app/termora/plugin/internal/wsl/WSLHostOptionsPane.kt index ca8a5fb..feecabf 100644 --- a/src/main/kotlin/app/termora/plugin/internal/wsl/WSLHostOptionsPane.kt +++ b/src/main/kotlin/app/termora/plugin/internal/wsl/WSLHostOptionsPane.kt @@ -1,6 +1,7 @@ package app.termora.plugin.internal.wsl import app.termora.* +import app.termora.highlight.KeywordHighlight import app.termora.plugin.internal.AltKeyModifier import app.termora.plugin.internal.BasicTerminalOption import com.formdev.flatlaf.FlatClientProperties @@ -47,6 +48,8 @@ internal open class WSLHostOptionsPane : OptionsPane() { "wsl-guid" to wsl.guid, "wsl-flavor" to wsl.flavor, "altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString() ?: AltKeyModifier.EightBit.name), + "keywordHighlightSetId" to ((terminalOption.highlightSetComboBox.selectedItem as? KeywordHighlight)?.id + ?: "-1"), ) ) @@ -76,6 +79,18 @@ internal open class WSLHostOptionsPane : OptionsPane() { } } + val altModifier = host.options.extras["altModifier"] ?: AltKeyModifier.EightBit.name + terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) } + .getOrNull() ?: AltKeyModifier.EightBit + + val keywordHighlightSetId = host.options.extras["keywordHighlightSetId"] + for (i in 0 until terminalOption.highlightSetComboBox.itemCount) { + val item = terminalOption.highlightSetComboBox.getItemAt(i) + if (item.id == keywordHighlightSetId) { + terminalOption.highlightSetComboBox.selectedItem = item + break + } + } } fun validateFields(): Boolean { diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties index 3607f1a..6a3872a 100644 --- a/src/main/resources/i18n/messages.properties +++ b/src/main/resources/i18n/messages.properties @@ -266,6 +266,7 @@ termora.terminal-logger.open-in-folder=Open in {0} # Highlight termora.highlight=Highlight Sets +termora.highlight.default-set=Default Set termora.highlight.text-color=Text Color termora.highlight.background-color=Background Color termora.highlight.keyword=Keyword diff --git a/src/main/resources/i18n/messages_ru_RU.properties b/src/main/resources/i18n/messages_ru_RU.properties index 14ebbd8..723bdee 100644 --- a/src/main/resources/i18n/messages_ru_RU.properties +++ b/src/main/resources/i18n/messages_ru_RU.properties @@ -230,6 +230,7 @@ termora.terminal-logger.open-in-folder=Открыть в {0} # Highlight termora.highlight=Персонализация +termora.highlight.default-set=Набор по умолчанию termora.highlight.text-color=Цвет Текста termora.highlight.background-color=Фоновый Цвет termora.highlight.keyword=Слово diff --git a/src/main/resources/i18n/messages_zh_CN.properties b/src/main/resources/i18n/messages_zh_CN.properties index c9cd093..27d961d 100644 --- a/src/main/resources/i18n/messages_zh_CN.properties +++ b/src/main/resources/i18n/messages_zh_CN.properties @@ -263,6 +263,7 @@ termora.terminal-logger.open-in-folder=在 {0} 中打开 # Highlight termora.highlight=关键词高亮 +termora.highlight.default-set=默认集 termora.highlight.text-color=文本颜色 termora.highlight.background-color=背景颜色 termora.highlight.keyword=关键词 diff --git a/src/main/resources/i18n/messages_zh_TW.properties b/src/main/resources/i18n/messages_zh_TW.properties index 0c01f78..a13eac9 100644 --- a/src/main/resources/i18n/messages_zh_TW.properties +++ b/src/main/resources/i18n/messages_zh_TW.properties @@ -259,6 +259,7 @@ termora.terminal-logger.open-in-folder=在 {0} 中打開 # Highlight termora.highlight=關鍵字高亮 +termora.highlight.default-set=預設集 termora.highlight.text-color=文字顏色 termora.highlight.background-color=背景顏色 termora.highlight.keyword=關鍵字