feat: supports custom editing of SFTP command (#210)

This commit is contained in:
hstyi
2025-02-12 16:33:37 +08:00
committed by GitHub
parent 189f8fb3ba
commit f7c49cde0c
6 changed files with 123 additions and 7 deletions

View File

@@ -14,6 +14,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.serialization.encodeToString
import org.apache.commons.io.IOUtils
import org.apache.commons.lang3.StringUtils
import org.slf4j.LoggerFactory
import java.io.File
import java.util.*
@@ -55,6 +56,7 @@ class Database private constructor(private val env: Environment) : Disposable {
val safetyProperties by lazy { SafetyProperties("Setting.SafetyProperties") }
val terminal by lazy { Terminal() }
val appearance by lazy { Appearance() }
val sftp by lazy { SFTP() }
val sync by lazy { Sync() }
private val doorman get() = Doorman.getInstance()
@@ -573,6 +575,19 @@ class Database private constructor(private val env: Environment) : Disposable {
}
/**
* SFTP
*/
inner class SFTP : Property("Setting.SFTP") {
/**
* 编辑命令
*/
var editCommand by StringPropertyDelegate(StringUtils.EMPTY)
}
/**
* 同步配置
*/

View File

@@ -109,6 +109,7 @@ class SettingsOptionsPane : OptionsPane() {
addOption(AppearanceOption())
addOption(TerminalOption())
addOption(KeyShortcutsOption())
addOption(SFTPOption())
addOption(CloudSyncOption())
addOption(DoormanOption())
addOption(AboutOption())
@@ -1172,6 +1173,63 @@ class SettingsOptionsPane : OptionsPane() {
}
}
private inner class SFTPOption : JPanel(BorderLayout()), Option {
val editCommandField = OutlineTextField(255)
private val sftp get() = database.sftp
init {
initView()
initEvents()
add(getCenterComponent(), BorderLayout.CENTER)
}
private fun initEvents() {
editCommandField.document.addDocumentListener(object : DocumentAdaptor() {
override fun changedUpdate(e: DocumentEvent) {
sftp.editCommand = editCommandField.text
}
})
}
private fun initView() {
if (SystemInfo.isWindows || SystemInfo.isLinux) {
editCommandField.placeholderText = "notepad {0}"
} else if (SystemInfo.isMacOS) {
editCommandField.placeholderText = "open -a TextEdit {0}"
}
editCommandField.text = sftp.editCommand
}
override fun getIcon(isSelected: Boolean): Icon {
return Icons.folder
}
override fun getTitle(): String {
return "SFTP"
}
override fun getJComponent(): JComponent {
return this
}
private fun getCenterComponent(): JComponent {
val layout = FormLayout(
"left:pref, $formMargin, default:grow, 30dlu",
"pref, $formMargin, pref, $formMargin, pref, $formMargin, pref, $formMargin, pref, $formMargin, pref"
)
val builder = FormBuilder.create().layout(layout).debug(false)
builder.add("${I18n.getString("termora.settings.sftp.edit-command")}:").xy(1, 1)
builder.add(editCommandField).xy(3, 1)
return builder.build()
}
}
private inner class AboutOption : JPanel(BorderLayout()), Option {
init {

View File

@@ -33,7 +33,9 @@ import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import java.io.File
import java.nio.file.*
import java.text.MessageFormat
import java.util.*
import java.util.regex.Pattern
import javax.swing.*
import javax.swing.table.DefaultTableCellRenderer
import kotlin.io.path.absolutePathString
@@ -489,8 +491,8 @@ class FileSystemPanel(
// 编辑
val edit = popupMenu.add(I18n.getString("termora.transport.table.contextmenu.edit"))
// 不是 Linux & 不是本地文件系统 & 包含文件
edit.isEnabled = !SystemInfo.isLinux && !tableModel.isLocalFileSystem && paths.any { !it.isDirectory }
// 不是本地文件系统 & 包含文件
edit.isEnabled = !tableModel.isLocalFileSystem && paths.any { !it.isDirectory }
edit.addActionListener {
val files = paths.filter { !it.isDirectory }
if (files.isNotEmpty()) {
@@ -615,19 +617,37 @@ class FileSystemPanel(
private fun editFileTransportListener(source: Path, localPath: Path): TransportListener {
return object : TransportListener {
private val sftp get() = Database.getDatabase().sftp
override fun onTransportChanged(transport: Transport) {
// 传输成功
if (transport.state == TransportState.Done) {
val transportManager = evt.getData(TransportDataProviders.TransportManager) ?: return
var lastModifiedTime = localPath.getLastModifiedTime().toMillis()
if (SystemInfo.isMacOS) {
try {
if (sftp.editCommand.isNotBlank()) {
ProcessBuilder(
parseCommand(
MessageFormat.format(
sftp.editCommand,
localPath.absolutePathString()
)
)
).start()
} else if (SystemInfo.isMacOS) {
ProcessBuilder("open", "-a", "TextEdit", localPath.absolutePathString()).start()
} else if (SystemInfo.isWindows) {
ProcessBuilder("notepad", localPath.absolutePathString()).start()
} else {
return
}
} catch (e: Exception) {
if (log.isErrorEnabled) {
log.error(e.message, e)
}
return
}
coroutineScope.launch(Dispatchers.IO) {
while (coroutineScope.isActive) {
@@ -657,6 +677,20 @@ class FileSystemPanel(
}
}
}
fun parseCommand(command: String): List<String> {
val result = mutableListOf<String>()
val matcher = Pattern.compile("\"([^\"]*)\"|(\\S+)").matcher(command)
while (matcher.find()) {
if (matcher.group(1) != null) {
result.add(matcher.group(1)) // 处理双引号部分
} else {
result.add(matcher.group(2).replace("\\\\ ", " "))
}
}
return result
}
}
}

View File

@@ -106,6 +106,9 @@ termora.settings.keymap.action=Action
termora.settings.keymap.already-exists=The shortcut [{0}] is already in use by [{1}]
termora.settings.sftp.edit-command=Edit Command
termora.settings.restart.title=Restart
termora.settings.restart.message=Changes will take effect after restarting the application

View File

@@ -110,6 +110,10 @@ termora.settings.keymap.shortcut=快捷键
termora.settings.keymap.action=操作
termora.settings.keymap.already-exists=快捷键 [{0}] 已经被 [{1}] 占用
termora.settings.sftp.edit-command=编辑命令
# Welcome
termora.welcome.my-hosts=我的主机
termora.welcome.contextmenu.open=打开

View File

@@ -62,6 +62,8 @@ termora.settings.keymap.shortcut=快捷鍵
termora.settings.keymap.action=操作
termora.settings.keymap.already-exists=快捷鍵 [{0}] 已經被 [{1}] 占用
termora.settings.sftp.edit-command=編輯命令
# Find everywhere
termora.find-everywhere=尋找