Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/main/kotlin/app/termora/plugin/PluginManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import app.termora.swingCoroutineScope
import app.termora.terminal.panel.vw.FloatingToolbarPlugin
import app.termora.transfer.internal.local.LocalPlugin
import app.termora.transfer.internal.sftp.SFTPPlugin
import app.termora.transfer.internal.wsl.WSLPlugin
import com.formdev.flatlaf.util.SystemInfo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -135,6 +136,11 @@ internal class PluginManager private constructor() {
// sftp transfer plugin
plugins.add(PluginDescriptor(SFTPPlugin(), origin = PluginOrigin.Internal, version = version))

// wsl transfer plugin
if (SystemUtils.IS_OS_WINDOWS) {
plugins.add(PluginDescriptor(WSLPlugin(), origin = PluginOrigin.Internal, version = version))
}

// floating
plugins.add(PluginDescriptor(FloatingToolbarPlugin(), origin = PluginOrigin.Internal, version = version))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ internal open class WSLHostOptionsPane : OptionsPane() {
val protocol = WSLProtocolProvider.PROTOCOL
val wsl = generalOption.hostComboBox.selectedItem as WSLDistribution
val host = wsl.distributionName
val wslPath = generalOption.pathTextField.text

val options = Options.Companion.Default.copy(
encoding = terminalOption.charsetComboBox.selectedItem as String,
Expand All @@ -50,6 +51,7 @@ internal open class WSLHostOptionsPane : OptionsPane() {
?: AltKeyModifier.EightBit.name),
"keywordHighlightSetId" to ((terminalOption.highlightSetComboBox.selectedItem as? KeywordHighlight)?.id
?: "-1"),
"wslPath" to wslPath
)
)

Expand All @@ -68,6 +70,7 @@ internal open class WSLHostOptionsPane : OptionsPane() {
generalOption.hostComboBox.selectedItem = host.host
generalOption.remarkTextArea.text = host.remark
generalOption.hostComboBox.selectedItem = null
generalOption.pathTextField.text = host.options.extras["wslPath"] ?: StringUtils.EMPTY
terminalOption.startupCommandTextField.text = host.options.startupCommand
terminalOption.environmentTextArea.text = host.options.env
terminalOption.charsetComboBox.selectedItem = host.options.encoding
Expand Down Expand Up @@ -134,15 +137,14 @@ internal open class WSLHostOptionsPane : OptionsPane() {
val nameTextField = OutlineTextField(128)
val hostComboBox = OutlineComboBox<WSLDistribution>()
val remarkTextArea = FixedLengthTextArea(512)
val pathTextField = OutlineTextField(512)

init {
initView()
initEvents()
}

private fun initView() {


hostComboBox.renderer = object : DefaultListCellRenderer() {
override fun getListCellRendererComponent(
list: JList<*>?,
Expand Down Expand Up @@ -171,6 +173,8 @@ internal open class WSLHostOptionsPane : OptionsPane() {
}
}

pathTextField.placeholderText = I18n.getString("termora.new-host.wsl.explorer-path.placeholder")

add(getCenterComponent(), BorderLayout.CENTER)
}

Expand Down Expand Up @@ -204,7 +208,7 @@ internal open class WSLHostOptionsPane : OptionsPane() {
private fun getCenterComponent(): JComponent {
val layout = FormLayout(
"left:pref, $FORM_MARGIN, default:grow",
"pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref"
"pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref,$FORM_MARGIN, pref"
)
remarkTextArea.setFocusTraversalKeys(
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
Expand All @@ -230,6 +234,9 @@ internal open class WSLHostOptionsPane : OptionsPane() {
.add("${I18n.getString("termora.new-host.wsl.distribution")}:").xy(1, rows)
.add(hostComboBox).xy(3, rows).apply { rows += step }

.add("${I18n.getString("termora.new-host.wsl.explorer-path")}:").xy(1, rows)
.add(pathTextField).xy(3, rows).apply { rows += step }

.add("${I18n.getString("termora.new-host.general.remark")}:").xy(1, rows)
.add(JScrollPane(remarkTextArea).apply { border = FlatTextBorder() })
.xy(3, rows).apply { rows += step }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package app.termora.protocol
import app.termora.plugin.internal.local.LocalProtocolProvider
import app.termora.plugin.internal.sftppty.SFTPPtyProtocolProvider
import app.termora.plugin.internal.ssh.SSHProtocolProvider
import app.termora.plugin.internal.wsl.WSLProtocolProvider
import app.termora.protocol.ProtocolProvider.Companion.providers
import app.termora.transfer.internal.local.LocalTransferProtocolProvider
import app.termora.transfer.internal.sftp.SFTPTransferProtocolProvider
import app.termora.transfer.internal.wsl.WSLTransferProtocolProvider
import org.apache.commons.lang3.StringUtils

interface TransferProtocolProvider : ProtocolProvider {
Expand All @@ -23,6 +25,10 @@ interface TransferProtocolProvider : ProtocolProvider {
StringUtils.equalsIgnoreCase(protocol, LocalTransferProtocolProvider.PROTOCOL)
) {
p = "file"
} else if (StringUtils.equalsIgnoreCase(protocol, WSLProtocolProvider.PROTOCOL) ||
StringUtils.equalsIgnoreCase(protocol, WSLTransferProtocolProvider.PROTOCOL)
) {
p = "wsl"
}

return providers.filterIsInstance<TransferProtocolProvider>()
Expand Down
5 changes: 4 additions & 1 deletion src/main/kotlin/app/termora/transfer/TransportPanel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import app.termora.plugin.ExtensionManager
import app.termora.plugin.internal.wsl.WSLHostTerminalTab
import app.termora.terminal.DataKey
import app.termora.transfer.TransportTableModel.Attributes
import app.termora.transfer.internal.wsl.WSLFileSystem
import app.termora.transfer.s3.S3FileAttributes
import com.formdev.flatlaf.FlatClientProperties
import com.formdev.flatlaf.extras.components.FlatToolBar
Expand Down Expand Up @@ -313,7 +314,9 @@ internal open class TransportPanel(
if (state != TransferTreeTableNode.State.Done && state != TransferTreeTableNode.State.Failed) return
val target = transfer.target()
if (loader.isLoaded()) {
if (target.fileSystem != loader.getSyncTransportSupport().getFileSystem()) return
if (target.fileSystem != loader.getSyncTransportSupport().getFileSystem() &&
loader.getSyncTransportSupport().getFileSystem() !is WSLFileSystem
) return
}
if (target.pathString == workdir?.pathString || target.parent.pathString == workdir?.pathString) {
val c = {
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/app/termora/transfer/TransportPopupMenu.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.apache.commons.io.IOUtils
import org.apache.commons.lang3.StringUtils
import org.apache.sshd.sftp.client.fs.SftpFileSystem
import java.awt.Window
import java.awt.datatransfer.DataFlavor
import java.awt.datatransfer.StringSelection
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
Expand Down Expand Up @@ -192,6 +193,7 @@ internal class TransportPopupMenu(
override fun popupMenuWillBecomeVisible(e: PopupMenuEvent?) {
pasteMenu.isEnabled = toolkit.systemClipboard
.isDataFlavorAvailable(TransportPanel.TransferTransferable.FLAVOR)
|| toolkit.systemClipboard.isDataFlavorAvailable(DataFlavor.javaFileListFlavor)
}

override fun popupMenuWillBecomeInvisible(e: PopupMenuEvent?) {
Expand Down
43 changes: 43 additions & 0 deletions src/main/kotlin/app/termora/transfer/internal/wsl/WSLFileSystem.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package app.termora.transfer.internal.wsl

import java.nio.file.*
import java.nio.file.attribute.UserPrincipalLookupService
import java.nio.file.spi.FileSystemProvider
import java.util.concurrent.atomic.AtomicBoolean

class WSLFileSystem : FileSystem() {
private val defaultFs = FileSystems.getDefault()

private val isOpen = AtomicBoolean(true)


override fun provider(): FileSystemProvider? = defaultFs.provider()
override fun close() {
isOpen.compareAndSet(true, false)

}

override fun isOpen(): Boolean {
return isOpen.get()
}

override fun isReadOnly() = defaultFs.isReadOnly
override fun getSeparator(): String? = defaultFs.separator
override fun getRootDirectories(): Iterable<Path?>? = defaultFs.rootDirectories
override fun getFileStores(): Iterable<FileStore?>? = defaultFs.fileStores
override fun supportedFileAttributeViews(): Set<String?>? = defaultFs.supportedFileAttributeViews()
override fun getPath(first: String, vararg more: String): Path =
defaultFs.getPath(first, *more)

override fun getPathMatcher(syntaxAndPattern: String): PathMatcher? =
defaultFs.getPathMatcher(syntaxAndPattern)

override fun getUserPrincipalLookupService(): UserPrincipalLookupService =
defaultFs.userPrincipalLookupService

override fun newWatchService(): WatchService =
defaultFs.newWatchService()

// override fun equals(other: Any?) = other == defaultFs
// override fun hashCode() = defaultFs.hashCode()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package app.termora.transfer.internal.wsl

import java.nio.file.FileSystem


class WSLFileSystemFactory {
companion object {
val instance by lazy { WSLFileSystemFactory() }
}

fun createWSLFileSystem(): FileSystem {
return WSLFileSystem()
}
}
20 changes: 20 additions & 0 deletions src/main/kotlin/app/termora/transfer/internal/wsl/WSLPlugin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package app.termora.transfer.internal.wsl

import app.termora.plugin.Extension
import app.termora.plugin.InternalPlugin
import app.termora.protocol.ProtocolProviderExtension

internal class WSLPlugin : InternalPlugin() {
init {
support.addExtension(ProtocolProviderExtension::class.java) { WSLProtocolProviderExtension.instance }
}

override fun getName(): String {
return "WSL Transfer"
}

override fun <T : Extension> getExtensions(clazz: Class<T>): List<T> {
return support.getExtensions(clazz)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package app.termora.transfer.internal.wsl

import app.termora.protocol.ProtocolProvider
import app.termora.protocol.ProtocolProviderExtension

internal class WSLProtocolProviderExtension private constructor() : ProtocolProviderExtension {
companion object {
val instance by lazy { WSLProtocolProviderExtension() }
}

override fun getProtocolProvider(): ProtocolProvider {
return WSLTransferProtocolProvider.instance
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package app.termora.transfer.internal.wsl

import app.termora.database.DatabaseManager
import app.termora.protocol.PathHandler
import app.termora.protocol.PathHandlerRequest
import app.termora.protocol.TransferProtocolProvider
import org.apache.commons.lang3.StringUtils
import java.nio.file.FileSystems

internal class WSLTransferProtocolProvider : TransferProtocolProvider {
companion object {
val instance by lazy { WSLTransferProtocolProvider() }
const val PROTOCOL = "wsl"
}

override fun isTransient(): Boolean {
return true
}

override fun getProtocol(): String {
return PROTOCOL
}

override fun createPathHandler(requester: PathHandlerRequest): PathHandler {
val wslPath = requester.host.options.extras["wslPath"] ?: StringUtils.EMPTY
// val fileSystem = FileSystems.getDefault()
val fileSystem = WSLFileSystemFactory.instance.createWSLFileSystem()
return PathHandler(fileSystem, fileSystem.getPath(wslPath))
}
}
9 changes: 6 additions & 3 deletions src/main/resources/i18n/messages.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
termora.title=Termora
termora.confirm=OK
termora.exit=退出
termora.exit=\u9000\u51FA
termora.cancel=Cancel
termora.copy=Copy
termora.paste=Paste
Expand Down Expand Up @@ -115,7 +115,7 @@ termora.settings.keymap=Keymap
termora.settings.keymap.shortcut=Shortcut
termora.settings.keymap.action=Action
termora.settings.keymap.already-exists=The shortcut [{0}] is already in use by [{1}]
termora.settings.keymap.question=Select a line, press the <font color=rgb({0},{1},{2})> (Backspace)</font> key to remove the shortcut
termora.settings.keymap.question=Select a line, press the <font color=rgb({0},{1},{2})> \u232B (Backspace)</font> key to remove the shortcut

termora.settings.sftp.edit-command=Edit Command
termora.settings.sftp.db-click-behavior=Double-click
Expand Down Expand Up @@ -213,11 +213,14 @@ termora.new-host.tunneling.add=Add
termora.new-host.tunneling.edit=${termora.keymgr.edit}
termora.new-host.tunneling.delete=${termora.remove}

termora.new-host.rdp.desktop-placeholder=Default full screen (e.g. 1920×1080)
termora.new-host.rdp.desktop-placeholder=Default full screen (e.g. 1920\u00D71080)
termora.new-host.rdp.resolution=Resolution


termora.new-host.wsl.distribution=DistroName
termora.new-host.wsl.explorer-path=Explorer Path
termora.new-host.wsl.explorer-path.placeholder=The path to the Windows Explorer


termora.new-host.test-connection=Test Connection
termora.new-host.test-connection-successful=Connection successful
Expand Down
Loading