Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
124acb2d7d chore(deps): bump com.h2database:h2 from 2.3.232 to 2.4.240
Bumps [com.h2database:h2](https://github.com/h2database/h2database) from 2.3.232 to 2.4.240.
- [Release notes](https://github.com/h2database/h2database/releases)
- [Commits](https://github.com/h2database/h2database/compare/version-2.3.232...version-2.4.240)

---
updated-dependencies:
- dependency-name: com.h2database:h2
  dependency-version: 2.4.240
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-24 01:17:14 +00:00
47 changed files with 147 additions and 277 deletions

View File

@@ -4,7 +4,7 @@ on: [ push, pull_request ]
env: env:
JBR_MAJOR: 21.0.8 JBR_MAJOR: 21.0.8
JBR_PATCH: b1163.69 JBR_PATCH: b1138.52
jobs: jobs:
build: build:

View File

@@ -9,14 +9,14 @@ env:
TERMORA_MAC_NOTARY: "${{ startsWith(github.event.head_commit.message, 'release: ') && github.repository == 'TermoraDev/termora' }}" TERMORA_MAC_NOTARY: "${{ startsWith(github.event.head_commit.message, 'release: ') && github.repository == 'TermoraDev/termora' }}"
TERMORA_MAC_NOTARY_KEYCHAIN_PROFILE: ${{ secrets.TERMORA_MAC_NOTARY_KEYCHAIN_PROFILE }} TERMORA_MAC_NOTARY_KEYCHAIN_PROFILE: ${{ secrets.TERMORA_MAC_NOTARY_KEYCHAIN_PROFILE }}
JBR_MAJOR: 21.0.8 JBR_MAJOR: 21.0.8
JBR_PATCH: b1163.69 JBR_PATCH: b1138.52
jobs: jobs:
build: build:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ macos-15-intel, macos-latest ] os: [ macos-15, macos-13 ]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:

View File

@@ -4,7 +4,7 @@ on: [ push, pull_request ]
env: env:
JBR_MAJOR: 21.0.8 JBR_MAJOR: 21.0.8
JBR_PATCH: b1163.69 JBR_PATCH: b1138.52
jobs: jobs:
build: build:

View File

@@ -1 +1 @@
2.0.0-beta.15 2.0.0-beta.14

View File

@@ -1,50 +1,50 @@
[versions] [versions]
kotlin = "2.3.0" kotlin = "2.2.20"
slf4j = "2.0.17" slf4j = "2.0.17"
pty4j = "0.13.10" pty4j = "0.13.10"
tinylog = "2.7.0" tinylog = "2.7.0"
kotlinx-coroutines = "1.10.2" kotlinx-coroutines = "1.10.2"
flatlaf = "3.7" flatlaf = "3.6.2"
kotlinx-serialization-json = "1.9.0" kotlinx-serialization-json = "1.9.0"
commons-codec = "1.20.0" commons-codec = "1.19.0"
commons-lang3 = "3.20.0" commons-lang3 = "3.19.0"
commons-csv = "1.14.1" commons-csv = "1.14.1"
commons-net = "3.12.0" commons-net = "3.12.0"
commons-text = "1.15.0" commons-text = "1.14.0"
commons-compress = "1.28.0" commons-compress = "1.28.0"
commons-vfs2 = "2.10.0" commons-vfs2 = "2.10.0"
swingx = "1.6.5-1" swingx = "1.6.5-1"
jgoodies-forms = "1.9.0" jgoodies-forms = "1.9.0"
jfa = "1.2.0" jfa = "1.2.0"
oshi = "6.9.1" oshi = "6.9.0"
versioncompare = "1.4.1" versioncompare = "1.4.1"
jna = "5.18.1" jna = "5.18.1"
jSystemThemeDetector = "3.9.1" jSystemThemeDetector = "3.9.1"
commons-io = "2.21.0" commons-io = "2.20.0"
jbr-api = "17.1.10.1" jbr-api = "17.1.10.1"
hutool = "5.8.40" hutool = "5.8.40"
jsch = "2.27.3" jsch = "2.27.3"
okhttp = "5.3.0" okhttp = "5.2.1"
sshj = "0.39.0" sshj = "0.39.0"
sshd-core = "2.15.0" sshd-core = "2.15.0"
jgit = "7.4.0.202509020913-r" jgit = "7.4.0.202509020913-r"
commonmark = "0.27.0" commonmark = "0.26.0"
jnafilechooser = "1.1.2" jnafilechooser = "1.1.2"
xodus = "2.0.1" xodus = "2.0.1"
bip39 = "1.0.9" bip39 = "1.0.9"
colorpicker = "2.0.1" colorpicker = "2.0.1"
rhino = "1.9.0" rhino = "1.8.0"
delight-rhino-sandbox = "0.2.1" delight-rhino-sandbox = "0.0.17"
testcontainers = "2.0.3" testcontainers = "2.0.0"
mixpanel = "1.7.0" mixpanel = "1.5.3"
jSerialComm = "2.11.4" jSerialComm = "2.11.2"
ini4j = "0.5.5-2" ini4j = "0.5.5-2"
restart4j = "0.0.1" restart4j = "0.0.1"
eddsa = "0.3.0" eddsa = "0.3.0"
exposed = "1.0.0-rc-4" exposed = "1.0.0-rc-2"
h2 = "2.3.232" h2 = "2.4.240"
sqlite = "3.50.3.0" sqlite = "3.50.3.0"
jug = "5.2.0" jug = "5.1.1"
semver4j = "6.0.0" semver4j = "6.0.0"
jsvg = "2.0.0" jsvg = "2.0.0"
dom4j = "2.2.0" dom4j = "2.2.0"
@@ -70,7 +70,7 @@ flatlafextras = { group = "com.formdev", name = "flatlaf-extras", version.ref =
flatlafswingx = { module = "com.formdev:flatlaf-swingx", version.ref = "flatlaf" } flatlafswingx = { module = "com.formdev:flatlaf-swingx", version.ref = "flatlaf" }
testcontainers-bom = { module = "org.testcontainers:testcontainers-bom", version.ref = "testcontainers" } testcontainers-bom = { module = "org.testcontainers:testcontainers-bom", version.ref = "testcontainers" }
testcontainers = { module = "org.testcontainers:testcontainers" } testcontainers = { module = "org.testcontainers:testcontainers" }
testcontainers-junit-jupiter = { module = "org.testcontainers:testcontainers-junit-jupiter" } testcontainers-junit-jupiter = { module = "org.testcontainers:junit-jupiter" }
swingx = { module = "org.swinglabs.swingx:swingx-all", version.ref = "swingx" } swingx = { module = "org.swinglabs.swingx:swingx-all", version.ref = "swingx" }
jgoodies-forms = { module = "com.jgoodies:jgoodies-forms", version.ref = "jgoodies-forms" } jgoodies-forms = { module = "com.jgoodies:jgoodies-forms", version.ref = "jgoodies-forms" }
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" } jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }

View File

@@ -8,7 +8,7 @@ project.version = "0.0.4"
dependencies { dependencies {
testImplementation(kotlin("test")) testImplementation(kotlin("test"))
implementation("com.qcloud:cos_api:5.6.260.1") implementation("com.qcloud:cos_api:5.6.257")
compileOnly(project(":")) compileOnly(project(":"))
} }

View File

@@ -10,7 +10,7 @@ project.version = "0.0.8"
dependencies { dependencies {
testImplementation(kotlin("test")) testImplementation(kotlin("test"))
compileOnly(project(":")) compileOnly(project(":"))
implementation("com.fifesoft:rsyntaxtextarea:3.6.1") implementation("com.fifesoft:rsyntaxtextarea:3.6.0")
implementation("com.fifesoft:languagesupport:3.4.0") implementation("com.fifesoft:languagesupport:3.4.0")
implementation("com.fifesoft:autocomplete:3.3.2") implementation("com.fifesoft:autocomplete:3.3.2")
} }

View File

@@ -7,7 +7,7 @@ project.version = "0.0.2"
dependencies { dependencies {
testImplementation(kotlin("test")) testImplementation(kotlin("test"))
compileOnly(project(":")) compileOnly(project(":"))
implementation("org.apache.commons:commons-pool2:2.13.0") implementation("org.apache.commons:commons-pool2:2.12.1")
testImplementation(project(":")) testImplementation(project(":"))
} }

View File

@@ -7,9 +7,9 @@ project.version = "0.0.8"
dependencies { dependencies {
testImplementation(kotlin("test")) testImplementation(kotlin("test"))
compileOnly(project(":")) compileOnly(project(":"))
implementation("com.maxmind.geoip2:geoip2:5.0.0") implementation("com.maxmind.geoip2:geoip2:4.4.0")
// https://github.com/hstyi/geolite2 // https://github.com/hstyi/geolite2
implementation("com.github.hstyi:geolite2:v1.0-202510270056") implementation("com.github.hstyi:geolite2:v1.0-202510200054")
} }
apply(from = "$rootDir/plugins/common.gradle.kts") apply(from = "$rootDir/plugins/common.gradle.kts")

View File

@@ -10,7 +10,7 @@ project.version = "0.0.5"
dependencies { dependencies {
testImplementation(kotlin("test")) testImplementation(kotlin("test"))
compileOnly(project(":")) compileOnly(project(":"))
implementation("com.fazecast:jSerialComm:2.11.4") implementation("com.fazecast:jSerialComm:2.11.2")
} }
apply(from = "$rootDir/plugins/common.gradle.kts") apply(from = "$rootDir/plugins/common.gradle.kts")

View File

@@ -2,7 +2,7 @@ plugins {
alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.jvm)
} }
project.version = "0.0.4" project.version = "0.0.3"
dependencies { dependencies {
testImplementation(kotlin("test")) testImplementation(kotlin("test"))

View File

@@ -42,7 +42,6 @@ class SMBHostOptionsPane : OptionsPane() {
sftpDefaultDirectory = sftpOption.defaultDirectoryField.text, sftpDefaultDirectory = sftpOption.defaultDirectoryField.text,
extras = mutableMapOf( extras = mutableMapOf(
"smb.share" to generalOption.shareTextField.text, "smb.share" to generalOption.shareTextField.text,
"smb.domain" to generalOption.domainTextField.text,
) )
) )
@@ -67,7 +66,6 @@ class SMBHostOptionsPane : OptionsPane() {
generalOption.remarkTextArea.text = host.remark generalOption.remarkTextArea.text = host.remark
generalOption.passwordTextField.text = host.authentication.password generalOption.passwordTextField.text = host.authentication.password
generalOption.shareTextField.text = host.options.extras["smb.share"] ?: StringUtils.EMPTY generalOption.shareTextField.text = host.options.extras["smb.share"] ?: StringUtils.EMPTY
generalOption.domainTextField.text = host.options.extras["smb.domain"] ?: StringUtils.EMPTY
sftpOption.defaultDirectoryField.text = host.options.sftpDefaultDirectory sftpOption.defaultDirectoryField.text = host.options.sftpDefaultDirectory
} }
@@ -116,7 +114,6 @@ class SMBHostOptionsPane : OptionsPane() {
val nameTextField = OutlineTextField(128) val nameTextField = OutlineTextField(128)
val shareTextField = OutlineTextField(256) val shareTextField = OutlineTextField(256)
val usernameTextField = OutlineComboBox<String>() val usernameTextField = OutlineComboBox<String>()
val domainTextField = OutlineTextField(128)
val hostTextField = OutlineTextField(255) val hostTextField = OutlineTextField(255)
val passwordTextField = OutlinePasswordField(255) val passwordTextField = OutlinePasswordField(255)
val remarkTextArea = FixedLengthTextArea(512) val remarkTextArea = FixedLengthTextArea(512)
@@ -191,9 +188,7 @@ class SMBHostOptionsPane : OptionsPane() {
.add(portTextField).xy(7, rows).apply { rows += step } .add(portTextField).xy(7, rows).apply { rows += step }
.add("${I18n.getString("termora.new-host.general.username")}:").xy(1, rows) .add("${I18n.getString("termora.new-host.general.username")}:").xy(1, rows)
.add(usernameTextField).xy(3, rows) .add(usernameTextField).xyw(3, rows, 5).apply { rows += step }
.add("${SMBI18n.getString("termora.plugins.smb.domain")}:").xy(5, rows)
.add(domainTextField).xy(7, rows).apply { rows += step }
.add("${I18n.getString("termora.new-host.general.password")}:").xy(1, rows) .add("${I18n.getString("termora.new-host.general.password")}:").xy(1, rows)
.add(passwordTextField).xyw(3, rows, 5).apply { rows += step } .add(passwordTextField).xyw(3, rows, 5).apply { rows += step }

View File

@@ -30,7 +30,6 @@ class SMBProtocolProvider private constructor() : TransferProtocolProvider {
val client = SMBClient() val client = SMBClient()
val host = requester.host val host = requester.host
val connection = client.connect(host.host, host.port) val connection = client.connect(host.host, host.port)
val domain = host.options.extras["smb.domain"] ?: StringUtils.EMPTY
val session = when (host.username) { val session = when (host.username) {
"Guest" -> connection.authenticate(AuthenticationContext.guest()) "Guest" -> connection.authenticate(AuthenticationContext.guest())
"Anonymous" -> connection.authenticate(AuthenticationContext.anonymous()) "Anonymous" -> connection.authenticate(AuthenticationContext.anonymous())
@@ -38,7 +37,7 @@ class SMBProtocolProvider private constructor() : TransferProtocolProvider {
AuthenticationContext( AuthenticationContext(
host.username, host.username,
host.authentication.password.toCharArray(), host.authentication.password.toCharArray(),
domain.ifBlank { null } null
) )
) )
} }

View File

@@ -1,2 +1 @@
termora.plugins.smb.share=Share name termora.plugins.smb.share=Share name
termora.plugins.smb.domain=Domain

View File

@@ -1,3 +1 @@
termora.plugins.smb.share=共享名称 termora.plugins.smb.share=共享名称
termora.plugins.smb.domain=域名

View File

@@ -1,3 +1 @@
termora.plugins.smb.share=共享名稱 termora.plugins.smb.share=共享名稱
termora.plugins.smb.domain=網域

View File

@@ -50,17 +50,6 @@ class ApplicationInitializr {
} }
} }
// https://github.com/TermoraDev/termora/issues/1254
if (System.getProperty(FlatSystemProperties.UI_SCALE).isNullOrBlank()) {
val scale = System.getenv("TERMORA_SCALE")
if (scale.isNullOrBlank().not()) {
if (NumberUtils.toDouble(scale, -1.0) > 0) {
System.setProperty(FlatSystemProperties.UI_SCALE_ENABLED, "true")
System.setProperty(FlatSystemProperties.UI_SCALE, scale)
}
}
}
// 启动 // 启动
val runtime = measureTimeMillis { ApplicationRunner().run() } val runtime = measureTimeMillis { ApplicationRunner().run() }
val log = LoggerFactory.getLogger(javaClass) val log = LoggerFactory.getLogger(javaClass)

View File

@@ -10,11 +10,15 @@ import com.formdev.flatlaf.extras.FlatInspector
import com.formdev.flatlaf.ui.FlatTableCellBorder import com.formdev.flatlaf.ui.FlatTableCellBorder
import com.formdev.flatlaf.util.SystemInfo import com.formdev.flatlaf.util.SystemInfo
import com.jthemedetecor.OsThemeDetector import com.jthemedetecor.OsThemeDetector
import com.mixpanel.mixpanelapi.ClientDelivery
import com.mixpanel.mixpanelapi.MessageBuilder
import com.mixpanel.mixpanelapi.MixpanelAPI
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
import org.apache.commons.lang3.LocaleUtils import org.apache.commons.lang3.LocaleUtils
import org.apache.commons.lang3.SystemUtils import org.apache.commons.lang3.SystemUtils
import org.json.JSONObject
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.awt.* import java.awt.*
import java.awt.desktop.AppReopenedEvent import java.awt.desktop.AppReopenedEvent
@@ -365,8 +369,61 @@ class ApplicationRunner {
if (Application.isUnknownVersion()) { if (Application.isUnknownVersion()) {
return return
} }
MixpanelService.getInstance().push("launch")
swingCoroutineScope.launch(Dispatchers.IO) {
try {
val properties = JSONObject()
properties.put("os", SystemUtils.OS_NAME)
if (SystemInfo.isLinux) {
properties.put("platform", "Linux")
} else if (SystemInfo.isWindows) {
properties.put("platform", "Windows")
} else if (SystemInfo.isMacOS) {
properties.put("platform", "macOS")
}
properties.put("version", Application.getVersion())
properties.put("language", Locale.getDefault().toString())
val message = MessageBuilder("0871335f59ee6d0eb246b008a20f9d1c")
.event(getAnalyticsUserID(), "launch", properties)
val delivery = ClientDelivery()
delivery.addMessage(message)
val endpoints = listOf(
"https://api-eu.mixpanel.com",
"https://api-in.mixpanel.com",
"https://api.mixpanel.com",
"http://api.mixpanel.com",
)
for (endpoint in endpoints) {
try {
MixpanelAPI(
"$endpoint/track",
"$endpoint/engage",
"$endpoint/groups"
).deliver(delivery, true)
break
} catch (e: Exception) {
if (log.isErrorEnabled) {
log.error(e.message, e)
}
continue
}
}
} catch (e: Exception) {
if (log.isErrorEnabled) {
log.error(e.message, e)
}
}
}
} }
private fun getAnalyticsUserID(): String {
val properties = DatabaseManager.getInstance().properties
var id = properties.getString("AnalyticsUserID")
if (id.isNullOrBlank()) {
id = randomUUID()
properties.putString("AnalyticsUserID", id)
}
return id
}
} }

View File

@@ -1,85 +0,0 @@
package app.termora
import app.termora.database.DatabaseManager
import com.formdev.flatlaf.util.SystemInfo
import com.mixpanel.mixpanelapi.ClientDelivery
import com.mixpanel.mixpanelapi.MessageBuilder
import com.mixpanel.mixpanelapi.MixpanelAPI
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.apache.commons.lang3.SystemUtils
import org.json.JSONObject
import org.slf4j.LoggerFactory
import java.util.*
internal class MixpanelService private constructor() {
companion object {
private val log = LoggerFactory.getLogger(MixpanelService::class.java)
fun getInstance(): MixpanelService {
return ApplicationScope.forApplicationScope().getOrCreate(MixpanelService::class) { MixpanelService() }
}
}
fun push(event: String, extras: Map<String, String> = emptyMap()) {
swingCoroutineScope.launch(Dispatchers.IO) {
try {
val properties = JSONObject()
for (entry in extras) {
properties.put(entry.key, entry.value)
}
properties.put("os", SystemUtils.OS_NAME)
if (SystemInfo.isLinux) {
properties.put("platform", "Linux")
} else if (SystemInfo.isWindows) {
properties.put("platform", "Windows")
} else if (SystemInfo.isMacOS) {
properties.put("platform", "macOS")
}
properties.put("version", Application.getVersion())
properties.put("language", Locale.getDefault().toString())
val message = MessageBuilder("0871335f59ee6d0eb246b008a20f9d1c")
.event(getAnalyticsUserID(), event, properties)
val delivery = ClientDelivery()
delivery.addMessage(message)
val endpoints = listOf(
"https://api-eu.mixpanel.com",
"https://api-in.mixpanel.com",
"https://api.mixpanel.com",
"http://api.mixpanel.com",
)
for (endpoint in endpoints) {
try {
MixpanelAPI(
"$endpoint/track",
"$endpoint/engage",
"$endpoint/groups"
).deliver(delivery, true)
break
} catch (e: Exception) {
if (log.isErrorEnabled) {
log.error(e.message, e)
}
continue
}
}
} catch (e: Exception) {
if (log.isErrorEnabled) {
log.error(e.message, e)
}
}
}
}
private fun getAnalyticsUserID(): String {
val properties = DatabaseManager.getInstance().properties
var id = properties.getString("AnalyticsUserID")
if (id.isNullOrBlank()) {
id = randomUUID()
properties.putString("AnalyticsUserID", id)
}
return id
}
}

View File

@@ -3,5 +3,5 @@ package app.termora
import app.termora.actions.AnActionEvent import app.termora.actions.AnActionEvent
import java.util.* import java.util.*
class OpenHostActionEvent(source: Any, val host: Host, event: EventObject, val tabIndex: Int = -1) : class OpenHostActionEvent(source: Any, val host: Host, event: EventObject) :
AnActionEvent(source, String(), event) AnActionEvent(source, String(), event)

View File

@@ -179,7 +179,7 @@ abstract class PtyHostTerminalTab(
val tab = createReconnectTerminalTab() val tab = createReconnectTerminalTab()
manager.addTerminalTab(index, tab, true) manager.addTerminalTab(index, tab, true)
manager.closeTerminalTab(this, disposable = true, reconnect = true) manager.closeTerminalTab(this, true)
if (tab is HostTerminalTab) { if (tab is HostTerminalTab) {
tab.start() tab.start()

View File

@@ -547,7 +547,6 @@ class SettingsOptionsPane : OptionsPane() {
rightClickComboBox.addItem("Copy") rightClickComboBox.addItem("Copy")
rightClickComboBox.addItem("CopyAndPaste") rightClickComboBox.addItem("CopyAndPaste")
rightClickComboBox.addItem("Nothing")
rightClickComboBox.selectedItem = terminalSetting.rightClick rightClickComboBox.selectedItem = terminalSetting.rightClick
@@ -577,8 +576,6 @@ class SettingsOptionsPane : OptionsPane() {
text = I18n.getString("termora.settings.terminal.right-click.copy") text = I18n.getString("termora.settings.terminal.right-click.copy")
} else if (value == "CopyAndPaste") { } else if (value == "CopyAndPaste") {
text = I18n.getString("termora.settings.terminal.right-click.copy-and-paste") text = I18n.getString("termora.settings.terminal.right-click.copy-and-paste")
}else if (value == "Nothing") {
text = I18n.getString("termora.settings.terminal.right-click.nothing")
} }
return super.getListCellRendererComponent(list, text, index, isSelected, cellHasFocus) return super.getListCellRendererComponent(list, text, index, isSelected, cellHasFocus)
} }

View File

@@ -141,28 +141,25 @@ class TerminalTabbed(
} }
private fun removeTabAt(index: Int, disposable: Boolean = true, reconnect: Boolean = false) { private fun removeTabAt(index: Int, disposable: Boolean = true) {
if (tabbedPane.isTabClosable(index)) { if (tabbedPane.isTabClosable(index)) {
val tab = tabs[index] val tab = tabs[index]
// 询问是否可以关闭 // 询问是否可以关闭
if (disposable) { if (disposable) {
// 如果是重连接,那么直接关闭不进行任何形式的询问 // 如果开启了关闭确认,那么直接询问用户
if (reconnect.not()) { if (appearance.confirmTabClose) {
// 如果开启了关闭确认,那么直接询问用户 if (OptionPane.showConfirmDialog(
if (appearance.confirmTabClose) { windowScope.window,
if (OptionPane.showConfirmDialog( I18n.getString("termora.tabbed.tab.close-prompt"),
windowScope.window, messageType = JOptionPane.QUESTION_MESSAGE,
I18n.getString("termora.tabbed.tab.close-prompt"), optionType = JOptionPane.OK_CANCEL_OPTION
messageType = JOptionPane.QUESTION_MESSAGE, ) != JOptionPane.OK_OPTION
optionType = JOptionPane.OK_CANCEL_OPTION ) {
) != JOptionPane.OK_OPTION
) {
return
}
} else if (!tab.willBeClose()) { // 如果没有开启则询问用户
return return
} }
} else if (!tab.willBeClose()) { // 如果没有开启则询问用户
return
} }
} }
@@ -236,7 +233,7 @@ class TerminalTabbed(
if (tab is HostTerminalTab) { if (tab is HostTerminalTab) {
actionManager actionManager
.getAction(OpenHostAction.OPEN_HOST) .getAction(OpenHostAction.OPEN_HOST)
.actionPerformed(OpenHostActionEvent(this, tab.host, evt, tabIndex + 1)) .actionPerformed(OpenHostActionEvent(this, tab.host, evt))
} }
} }
@@ -364,7 +361,7 @@ class TerminalTabbed(
} }
} }
override fun indexOfTerminalTab(tab: TerminalTab): Int { override fun indexOfTerminalTab(tab: TerminalTab):Int {
return tabbedPane.indexOfComponent(tab.getJComponent()) return tabbedPane.indexOfComponent(tab.getJComponent())
} }
@@ -454,10 +451,10 @@ class TerminalTabbed(
} }
} }
override fun closeTerminalTab(tab: TerminalTab, disposable: Boolean, reconnect: Boolean) { override fun closeTerminalTab(tab: TerminalTab, disposable: Boolean) {
for (i in 0 until tabs.size) { for (i in 0 until tabs.size) {
if (tabs[i] == tab) { if (tabs[i] == tab) {
removeTabAt(i, disposable, reconnect) removeTabAt(i, disposable)
break break
} }
} }

View File

@@ -6,7 +6,7 @@ interface TerminalTabbedManager {
fun getSelectedTerminalTab(): TerminalTab? fun getSelectedTerminalTab(): TerminalTab?
fun getTerminalTabs(): List<TerminalTab> fun getTerminalTabs(): List<TerminalTab>
fun setSelectedTerminalTab(tab: TerminalTab) fun setSelectedTerminalTab(tab: TerminalTab)
fun closeTerminalTab(tab: TerminalTab, disposable: Boolean = true, reconnect: Boolean = false) fun closeTerminalTab(tab: TerminalTab, disposable: Boolean = true)
fun refreshTerminalTabs() fun refreshTerminalTabs()
fun indexOfTerminalTab(tab: TerminalTab): Int fun indexOfTerminalTab(tab: TerminalTab): Int
} }

View File

@@ -67,11 +67,6 @@ class PullService private constructor() : SyncService(), Disposable, Application
private var lastChangeHash = StringUtils.EMPTY private var lastChangeHash = StringUtils.EMPTY
private fun pullChanges() { private fun pullChanges() {
if (accountManager.isLocally()) {
return
}
val hash: String val hash: String
try { try {

View File

@@ -56,12 +56,7 @@ class OpenHostAction : AnAction() {
if (tab == null) return if (tab == null) return
if (evt.tabIndex >= 0) { terminalTabbedManager.addTerminalTab(tab)
terminalTabbedManager.addTerminalTab(evt.tabIndex, tab)
} else {
terminalTabbedManager.addTerminalTab(tab)
}
if (tab is PtyHostTerminalTab) { if (tab is PtyHostTerminalTab) {
tab.start() tab.start()
} }

View File

@@ -20,10 +20,6 @@ class TerminalCopyAction : AnAction() {
override fun actionPerformed(evt: AnActionEvent) { override fun actionPerformed(evt: AnActionEvent) {
val terminalPanel = evt.getData(DataProviders.TerminalPanel) ?: return val terminalPanel = evt.getData(DataProviders.TerminalPanel) ?: return
val selectionModel = terminalPanel.terminal.getSelectionModel()
if (!selectionModel.hasSelection()) {
return
}
val text = terminalPanel.copy() val text = terminalPanel.copy()
val systemClipboard = terminalPanel.toolkit.systemClipboard val systemClipboard = terminalPanel.toolkit.systemClipboard
@@ -57,4 +53,4 @@ class TerminalCopyAction : AnAction() {
} }
} }

View File

@@ -27,14 +27,12 @@ class KeyboardInteractiveDialog(
isModal = true isModal = true
isResizable = true isResizable = true
controlsVisible = false controlsVisible = false
title = I18n.getString("termora.new-host.title")
init() init()
pack() pack()
size = Dimension(max(300, size.width), size.height) size = Dimension(max(300, size.width), size.height)
// fix https://github.com/TermoraDev/termora/issues/1311
pack()
setLocationRelativeTo(null) setLocationRelativeTo(null)
} }

View File

@@ -30,7 +30,6 @@ class TerminalUserInteraction(
) )
dialog.setLocationRelativeTo(owner) dialog.setLocationRelativeTo(owner)
dialog.title = instruction ?: name ?: "OTP" dialog.title = instruction ?: name ?: "OTP"
dialog.title = StringUtils.defaultIfBlank(dialog.title, "OTP")
passwords[i] = dialog.getText() passwords[i] = dialog.getText()
if (passwords[i].isBlank()) { if (passwords[i].isBlank()) {
break break

View File

@@ -29,10 +29,8 @@ class KeymapPanel : JPanel(BorderLayout()) {
private val copyBtn = JButton(Icons.copy) private val copyBtn = JButton(Icons.copy)
private val renameBtn = JButton(Icons.edit) private val renameBtn = JButton(Icons.edit)
private val deleteBtn = JButton(Icons.delete) private val deleteBtn = JButton(Icons.delete)
private val infoBtn = JButton(Icons.questionMark)
private val database get() = DatabaseManager.getInstance() private val database get() = DatabaseManager.getInstance()
private val allowKeyCodes = mutableSetOf<Int>() private val allowKeyCodes = mutableSetOf<Int>()
private val owner get() = SwingUtilities.getWindowAncestor(this)
init { init {
initView() initView()
@@ -91,8 +89,8 @@ class KeymapPanel : JPanel(BorderLayout()) {
box.add(copyBtn) box.add(copyBtn)
box.add(renameBtn) box.add(renameBtn)
box.add(deleteBtn) box.add(deleteBtn)
box.add(infoBtn)
box.add(Box.createHorizontalGlue()) box.add(Box.createHorizontalGlue())
box.border = BorderFactory.createEmptyBorder(0, 0, 6, 0)
add(box, BorderLayout.NORTH) add(box, BorderLayout.NORTH)
add(scrollPane, BorderLayout.CENTER) add(scrollPane, BorderLayout.CENTER)
@@ -107,12 +105,6 @@ class KeymapPanel : JPanel(BorderLayout()) {
} }
}) })
infoBtn.addActionListener {
val color = UIManager.getColor("TextField.placeholderForeground")
val msg = I18n.getString("termora.settings.keymap.question", color.red, color.green, color.blue)
OptionPane.showMessageDialog(owner, msg)
}
copyBtn.addActionListener { copyBtn.addActionListener {
val keymap = getCurrentKeymap() val keymap = getCurrentKeymap()
if (keymap != null) { if (keymap != null) {

View File

@@ -185,13 +185,6 @@ class PluginPanel(val descriptor: PluginPluginDescriptor) : JPanel(), Disposable
} }
} }
MixpanelService.getInstance().push(
"uninstall-plugin", mapOf(
"pluginName" to descriptor.plugin.getName(),
"pluginVersion" to descriptor.version.toString(),
)
)
// 询问是否重启 // 询问是否重启
TermoraRestarter.getInstance().scheduleRestart(owner) TermoraRestarter.getInstance().scheduleRestart(owner)
} else { } else {
@@ -234,13 +227,6 @@ class PluginPanel(val descriptor: PluginPluginDescriptor) : JPanel(), Disposable
} }
}, button == updateButton) }, button == updateButton)
MixpanelService.getInstance().push(
"${if (button == installButton) "install" else "update"}-plugin", mapOf(
"pluginName" to descriptor.plugin.getName(),
"pluginVersion" to descriptor.version.toString(),
)
)
withContext(Dispatchers.Swing) { withContext(Dispatchers.Swing) {
installed.add(descriptor.id) installed.add(descriptor.id)

View File

@@ -10,8 +10,6 @@ import kotlinx.coroutines.launch
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
import org.apache.commons.io.IOUtils import org.apache.commons.io.IOUtils
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import org.apache.commons.lang3.Strings
import org.apache.commons.lang3.SystemUtils
import java.awt.datatransfer.DataFlavor import java.awt.datatransfer.DataFlavor
import java.awt.datatransfer.StringSelection import java.awt.datatransfer.StringSelection
import java.net.URI import java.net.URI
@@ -66,15 +64,7 @@ internal class RDPProtocolProvider private constructor() : GenericProtocolProvid
} }
val sb = StringBuilder() val sb = StringBuilder()
sb.append("full address:s:") sb.append("full address:s:").append(host.host).append(':').append(host.port).appendLine()
if (SystemUtils.IS_OS_WINDOWS && Strings.CI.contains(host.host, ":")) {
var newHost = Strings.CI.removeStart(host.host, "[")
newHost = Strings.CI.removeEnd(newHost, "]")
sb.append('[').append(newHost).append(']')
} else {
sb.append(host.host)
}
sb.append(':').append(host.port).appendLine()
sb.append("username:s:").append(host.username).appendLine() sb.append("username:s:").append(host.username).appendLine()
val desktop = host.options.extras["desktop"] val desktop = host.options.extras["desktop"]
if (desktop.isNullOrBlank().not()) { if (desktop.isNullOrBlank().not()) {

View File

@@ -27,14 +27,9 @@ class CloneSessionTerminalTabbedContextMenuExtension private constructor() : Ter
cloneSession.addActionListener(object : AnAction() { cloneSession.addActionListener(object : AnAction() {
override fun actionPerformed(evt: AnActionEvent) { override fun actionPerformed(evt: AnActionEvent) {
val terminalTabbedManager = evt.getData(DataProviders.TerminalTabbedManager) ?: return val terminalTabbedManager = evt.getData(DataProviders.TerminalTabbedManager) ?: return
val index = terminalTabbedManager.indexOfTerminalTab(tab)
val handler = c.copy(channel = null) val handler = c.copy(channel = null)
val newTab = SSHTerminalTab(windowScope, tab.host, handler) val newTab = SSHTerminalTab(windowScope, tab.host, handler)
if (index >= 0) { terminalTabbedManager.addTerminalTab(newTab)
terminalTabbedManager.addTerminalTab(index + 1, newTab)
} else {
terminalTabbedManager.addTerminalTab(newTab)
}
newTab.start() newTab.start()
} }
}) })

View File

@@ -332,12 +332,6 @@ class ControlSequenceIntroducerProcessor(terminal: Terminal, reader: TerminalRea
var top = sr.getOrElse(0) { 1 } var top = sr.getOrElse(0) { 1 }
var bottom = sr.getOrElse(1) { terminalModel.getRows() } var bottom = sr.getOrElse(1) { terminalModel.getRows() }
// ";r" https://vt100.net/docs/vt510-rm/DECSTBM.html
if (sr.size == 1 && args.startsWith(';')) {
bottom = top
top = 1
}
if (bottom <= top) { if (bottom <= top) {
if (log.isWarnEnabled) { if (log.isWarnEnabled) {
log.warn("Set Scrolling Region Error. top: $top , bottom: $bottom") log.warn("Set Scrolling Region Error. top: $top , bottom: $bottom")

View File

@@ -1,6 +1,5 @@
package app.termora.terminal.panel package app.termora.terminal.panel
import app.termora.actions.TerminalCopyAction
import app.termora.keymap.KeyShortcut import app.termora.keymap.KeyShortcut
import app.termora.keymap.KeymapManager import app.termora.keymap.KeymapManager
import app.termora.plugin.internal.AltKeyModifier import app.termora.plugin.internal.AltKeyModifier
@@ -72,7 +71,6 @@ class TerminalPanelKeyAdapter(
} }
val keyStroke = KeyStroke.getKeyStrokeForEvent(e) val keyStroke = KeyStroke.getKeyStrokeForEvent(e)
val keymapActions = activeKeymap.getActionIds(KeyShortcut(keyStroke))
for (action in terminalPanel.getTerminalActions()) { for (action in terminalPanel.getTerminalActions()) {
if (action.test(keyStroke, e)) { if (action.test(keyStroke, e)) {
action.actionPerformed(e) action.actionPerformed(e)
@@ -106,9 +104,7 @@ class TerminalPanelKeyAdapter(
} }
// 如果命中了全局快捷键,那么不处理 // 如果命中了全局快捷键,那么不处理
val copyShortcutWithoutSelection = if (keyStroke.modifiers != 0 && activeKeymap.getActionIds(KeyShortcut(keyStroke)).isNotEmpty()) {
keymapActions.contains(TerminalCopyAction.COPY) && terminal.getSelectionModel().hasSelection().not()
if (keyStroke.modifiers != 0 && keymapActions.isNotEmpty() && !copyShortcutWithoutSelection) {
return return
} }
@@ -163,4 +159,4 @@ class TerminalPanelKeyAdapter(
return Character.toLowerCase(e.keyCode.toChar()) return Character.toLowerCase(e.keyCode.toChar())
} }
} }

View File

@@ -53,31 +53,30 @@ class TerminalPanelMouseSelectionAdapter(private val terminalPanel: TerminalPane
if (SwingUtilities.isRightMouseButton(e)) { if (SwingUtilities.isRightMouseButton(e)) {
// 如果有选中并且开启了选中复制,那么右键直接是粘贴 // 如果有选中并且开启了选中复制,那么右键直接是粘贴
if (selectionModel.hasSelection() && isSelectCopy.not()) { if (selectionModel.hasSelection() && isSelectCopy.not()) {
if (rightClickMode != "Nothing") { triggerCopyAction(
triggerCopyAction( KeyEvent(
e.component,
KeyEvent.KEY_PRESSED,
e.`when`,
e.modifiersEx,
KeyEvent.VK_C,
'C'
)
)
if (rightClickMode == "CopyAndPaste") {
triggerPasteAction(
KeyEvent( KeyEvent(
e.component, e.component,
KeyEvent.KEY_PRESSED, KeyEvent.KEY_PRESSED,
e.`when`, e.`when`,
e.modifiersEx, e.modifiersEx,
KeyEvent.VK_C, KeyEvent.VK_V,
'C' 'V'
) )
) )
if (rightClickMode == "CopyAndPaste") {
triggerPasteAction(
KeyEvent(
e.component,
KeyEvent.KEY_PRESSED,
e.`when`,
e.modifiersEx,
KeyEvent.VK_V,
'V'
)
)
}
} }
} else { } else {
// paste // paste
triggerPasteAction( triggerPasteAction(

View File

@@ -46,7 +46,6 @@ class TransferAnAction : AnAction(I18n.getString("termora.transport.sftp"), Icon
val panel = tabbed.getTransportPanel(i) ?: continue val panel = tabbed.getTransportPanel(i) ?: continue
if (panel.host.id == host.id) { if (panel.host.id == host.id) {
tabbed.selectedIndex = i tabbed.selectedIndex = i
terminalTabbedManager.setSelectedTerminalTab(sftpTab)
return return
} }
} }

View File

@@ -1,7 +1,7 @@
package app.termora.transfer package app.termora.transfer
import app.termora.WindowScope
import app.termora.plugin.Extension import app.termora.plugin.Extension
import java.awt.Window
import java.nio.file.FileSystem import java.nio.file.FileSystem
import java.nio.file.Path import java.nio.file.Path
import javax.swing.JMenuItem import javax.swing.JMenuItem
@@ -14,7 +14,7 @@ internal interface TransportContextMenuExtension : Extension {
* @param fileSystem 为 null 表示可能已经断线,处于不可用状态 * @param fileSystem 为 null 表示可能已经断线,处于不可用状态
*/ */
fun createJMenuItem( fun createJMenuItem(
window: Window, windowScope: WindowScope,
fileSystem: FileSystem?, fileSystem: FileSystem?,
popupMenu: TransportPopupMenu, popupMenu: TransportPopupMenu,
files: List<Pair<Path, TransportTableModel.Attributes>> files: List<Pair<Path, TransportTableModel.Attributes>>

View File

@@ -108,7 +108,7 @@ internal class TransportPopupMenu(
for (extension in extensionManager.getExtensions(TransportContextMenuExtension::class.java)) { for (extension in extensionManager.getExtensions(TransportContextMenuExtension::class.java)) {
try { try {
val menu = extension.createJMenuItem( val menu = extension.createJMenuItem(
owner, ApplicationScope.forWindowScope(owner),
fileSystem, fileSystem,
this, this,
files files

View File

@@ -1,6 +1,7 @@
package app.termora.transfer.internal.sftp package app.termora.transfer.internal.sftp
import app.termora.I18n import app.termora.I18n
import app.termora.WindowScope
import app.termora.actions.AnAction import app.termora.actions.AnAction
import app.termora.actions.AnActionEvent import app.termora.actions.AnActionEvent
import app.termora.randomUUID import app.termora.randomUUID
@@ -8,7 +9,6 @@ import app.termora.transfer.*
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import org.apache.sshd.common.file.util.MockPath import org.apache.sshd.common.file.util.MockPath
import org.apache.sshd.sftp.client.fs.SftpFileSystem import org.apache.sshd.sftp.client.fs.SftpFileSystem
import java.awt.Window
import java.nio.file.FileSystem import java.nio.file.FileSystem
import java.nio.file.Path import java.nio.file.Path
import javax.swing.JMenu import javax.swing.JMenu
@@ -23,7 +23,7 @@ internal class CompressTransportContextMenuExtension private constructor() : Tra
} }
override fun createJMenuItem( override fun createJMenuItem(
window: Window, windowScope: WindowScope,
fileSystem: FileSystem?, fileSystem: FileSystem?,
popupMenu: TransportPopupMenu, popupMenu: TransportPopupMenu,
files: List<Pair<Path, TransportTableModel.Attributes>> files: List<Pair<Path, TransportTableModel.Attributes>>

View File

@@ -1,13 +1,13 @@
package app.termora.transfer.internal.sftp package app.termora.transfer.internal.sftp
import app.termora.I18n import app.termora.I18n
import app.termora.WindowScope
import app.termora.actions.AnAction import app.termora.actions.AnAction
import app.termora.actions.AnActionEvent import app.termora.actions.AnActionEvent
import app.termora.randomUUID import app.termora.randomUUID
import app.termora.transfer.* import app.termora.transfer.*
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import org.apache.sshd.sftp.client.fs.SftpFileSystem import org.apache.sshd.sftp.client.fs.SftpFileSystem
import java.awt.Window
import java.nio.file.FileSystem import java.nio.file.FileSystem
import java.nio.file.Path import java.nio.file.Path
import javax.swing.JMenu import javax.swing.JMenu
@@ -21,7 +21,7 @@ internal class ExtractTransportContextMenuExtension private constructor() : Tran
} }
override fun createJMenuItem( override fun createJMenuItem(
window: Window, windowScope: WindowScope,
fileSystem: FileSystem?, fileSystem: FileSystem?,
popupMenu: TransportPopupMenu, popupMenu: TransportPopupMenu,
files: List<Pair<Path, TransportTableModel.Attributes>> files: List<Pair<Path, TransportTableModel.Attributes>>

View File

@@ -3,11 +3,11 @@ package app.termora.transfer.internal.sftp
import app.termora.I18n import app.termora.I18n
import app.termora.Icons import app.termora.Icons
import app.termora.OptionPane import app.termora.OptionPane
import app.termora.WindowScope
import app.termora.transfer.TransportContextMenuExtension import app.termora.transfer.TransportContextMenuExtension
import app.termora.transfer.TransportPopupMenu import app.termora.transfer.TransportPopupMenu
import app.termora.transfer.TransportTableModel import app.termora.transfer.TransportTableModel
import org.apache.sshd.sftp.client.fs.SftpFileSystem import org.apache.sshd.sftp.client.fs.SftpFileSystem
import java.awt.Window
import java.nio.file.FileSystem import java.nio.file.FileSystem
import java.nio.file.Path import java.nio.file.Path
import javax.swing.JMenuItem import javax.swing.JMenuItem
@@ -19,7 +19,7 @@ internal class RmrfTransportContextMenuExtension private constructor() : Transpo
} }
override fun createJMenuItem( override fun createJMenuItem(
window: Window, windowScope: WindowScope,
fileSystem: FileSystem?, fileSystem: FileSystem?,
popupMenu: TransportPopupMenu, popupMenu: TransportPopupMenu,
files: List<Pair<Path, TransportTableModel.Attributes>> files: List<Pair<Path, TransportTableModel.Attributes>>
@@ -31,7 +31,7 @@ internal class RmrfTransportContextMenuExtension private constructor() : Transpo
val rmrfMenu = JMenuItem("rm -rf", Icons.warningIntroduction) val rmrfMenu = JMenuItem("rm -rf", Icons.warningIntroduction)
rmrfMenu.addActionListener { rmrfMenu.addActionListener {
if (OptionPane.showConfirmDialog( if (OptionPane.showConfirmDialog(
window, windowScope.window,
I18n.getString("termora.transport.table.contextmenu.rm-warning"), I18n.getString("termora.transport.table.contextmenu.rm-warning"),
messageType = JOptionPane.ERROR_MESSAGE messageType = JOptionPane.ERROR_MESSAGE
) == JOptionPane.YES_OPTION ) == JOptionPane.YES_OPTION

View File

@@ -59,7 +59,6 @@ termora.settings.terminal.hyperlink=Hyperlink
termora.settings.terminal.select-copy=Select copy termora.settings.terminal.select-copy=Select copy
termora.settings.terminal.right-click=Right click termora.settings.terminal.right-click=Right click
termora.settings.terminal.right-click.copy-and-paste=Copy and Paste termora.settings.terminal.right-click.copy-and-paste=Copy and Paste
termora.settings.terminal.right-click.nothing=Nothing
termora.settings.terminal.right-click.copy=${termora.copy} termora.settings.terminal.right-click.copy=${termora.copy}
termora.settings.terminal.cursor-style=Cursor type termora.settings.terminal.cursor-style=Cursor type
termora.settings.terminal.cursor-blink=Cursor blink termora.settings.terminal.cursor-blink=Cursor blink
@@ -115,7 +114,7 @@ termora.settings.keymap=Keymap
termora.settings.keymap.shortcut=Shortcut termora.settings.keymap.shortcut=Shortcut
termora.settings.keymap.action=Action termora.settings.keymap.action=Action
termora.settings.keymap.already-exists=The shortcut [{0}] is already in use by [{1}] 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.sftp.edit-command=Edit Command termora.settings.sftp.edit-command=Edit Command
termora.settings.sftp.db-click-behavior=Double-click termora.settings.sftp.db-click-behavior=Double-click

View File

@@ -81,7 +81,6 @@ termora.settings.terminal.hyperlink=Ссылки
termora.settings.terminal.select-copy=Копировать выделенное termora.settings.terminal.select-copy=Копировать выделенное
termora.settings.terminal.right-click=правой кнопкой мыши termora.settings.terminal.right-click=правой кнопкой мыши
termora.settings.terminal.right-click.copy-and-paste=Копировать и вставить termora.settings.terminal.right-click.copy-and-paste=Копировать и вставить
termora.settings.terminal.right-click.nothing=никто
termora.settings.terminal.cursor-style=Вид курсора termora.settings.terminal.cursor-style=Вид курсора
termora.settings.terminal.cursor-blink=Мигать курсором termora.settings.terminal.cursor-blink=Мигать курсором
termora.settings.terminal.local-shell=Локальный терминал termora.settings.terminal.local-shell=Локальный терминал
@@ -100,7 +99,7 @@ termora.settings.keymap=Горяиче клавиши
termora.settings.keymap.shortcut=Комбинация termora.settings.keymap.shortcut=Комбинация
termora.settings.keymap.action=Команда termora.settings.keymap.action=Команда
termora.settings.keymap.already-exists=Комбинация [{0}] уже используется [{1}] termora.settings.keymap.already-exists=Комбинация [{0}] уже используется [{1}]
termora.settings.keymap.question=Выберите строку и нажмите <font color=rgb({0},{1},{2})> ⌫ (клавишу Backspace)</font>, чтобы удалить сочетание клавиш
termora.settings.sftp.edit-command=Редактировать команду termora.settings.sftp.edit-command=Редактировать команду
termora.settings.sftp.db-click-behavior=двойной щелчок termora.settings.sftp.db-click-behavior=двойной щелчок

View File

@@ -73,7 +73,6 @@ termora.settings.terminal.hyperlink=超链接
termora.settings.terminal.select-copy=选中复制 termora.settings.terminal.select-copy=选中复制
termora.settings.terminal.right-click=右键点击 termora.settings.terminal.right-click=右键点击
termora.settings.terminal.right-click.copy-and-paste=复制 & 粘贴 termora.settings.terminal.right-click.copy-and-paste=复制 & 粘贴
termora.settings.terminal.right-click.nothing=无操作
termora.settings.terminal.cursor-style=光标样式 termora.settings.terminal.cursor-style=光标样式
termora.settings.terminal.cursor-blink=光标闪烁 termora.settings.terminal.cursor-blink=光标闪烁
termora.settings.terminal.local-shell=本地终端 termora.settings.terminal.local-shell=本地终端
@@ -126,7 +125,7 @@ termora.settings.keymap=键盘
termora.settings.keymap.shortcut=快捷键 termora.settings.keymap.shortcut=快捷键
termora.settings.keymap.action=操作 termora.settings.keymap.action=操作
termora.settings.keymap.already-exists=快捷键 [{0}] 已经被 [{1}] 占用 termora.settings.keymap.already-exists=快捷键 [{0}] 已经被 [{1}] 占用
termora.settings.keymap.question=选中一行,按下 <font color=rgb({0},{1},{2})> ⌫ (退格键)</font> 移除快捷键
termora.settings.sftp.edit-command=编辑命令 termora.settings.sftp.edit-command=编辑命令
termora.settings.sftp.db-click-behavior=双击行为 termora.settings.sftp.db-click-behavior=双击行为

View File

@@ -55,7 +55,6 @@ termora.settings.keymap=鍵盤
termora.settings.keymap.shortcut=快捷鍵 termora.settings.keymap.shortcut=快捷鍵
termora.settings.keymap.action=操作 termora.settings.keymap.action=操作
termora.settings.keymap.already-exists=快捷鍵 [{0}] 已經被 [{1}] 占用 termora.settings.keymap.already-exists=快捷鍵 [{0}] 已經被 [{1}] 占用
termora.settings.keymap.question=選取一行,按下 <font color=rgb({0},{1},{2})> ⌫ (退格鍵)</font> 移除快速鍵
termora.settings.sftp.edit-command=編輯命令 termora.settings.sftp.edit-command=編輯命令
termora.settings.sftp.db-click-behavior=按兩下行為 termora.settings.sftp.db-click-behavior=按兩下行為
@@ -85,7 +84,6 @@ termora.settings.terminal.hyperlink=超連結
termora.settings.terminal.select-copy=選取複製 termora.settings.terminal.select-copy=選取複製
termora.settings.terminal.right-click=右鍵點擊 termora.settings.terminal.right-click=右鍵點擊
termora.settings.terminal.right-click.copy-and-paste=複製 & 貼上 termora.settings.terminal.right-click.copy-and-paste=複製 & 貼上
termora.settings.terminal.right-click.nothing=無操作
termora.settings.terminal.cursor-style=遊標風格 termora.settings.terminal.cursor-style=遊標風格
termora.settings.terminal.cursor-blink=遊標閃爍 termora.settings.terminal.cursor-blink=遊標閃爍
termora.settings.terminal.local-shell=本地端 termora.settings.terminal.local-shell=本地端

View File

@@ -1,5 +1,5 @@
FROM linuxserver/openssh-server:9.3_p2-r1-ls147 FROM linuxserver/openssh-server:9.3_p2-r1-ls147
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \ RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk update && apk add wget tmux gcc zip p7zip g++ git make zsh htop stress-ng inetutils-telnet xclock xcalc xorg-server xinit && wget https://ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz \ && apk update && apk add wget tmux gcc zip p7zip g++ git make zsh htop stress-ng inetutils-telnet xclock xcalc xorg-server xinit && wget https://ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz \
&& tar -xf lrzsz-0.12.20.tar.gz && cd lrzsz-0.12.20 && ./configure && make && make install \ && tar -xf lrzsz-0.12.20.tar.gz && cd lrzsz-0.12.20 && ./configure && make && make install \
&& ln -s /usr/local/bin/lrz /usr/local/bin/rz && ln -s /usr/local/bin/lsz /usr/local/bin/sz && ln -s /usr/local/bin/lrz /usr/local/bin/rz && ln -s /usr/local/bin/lsz /usr/local/bin/sz
@@ -7,6 +7,3 @@ RUN sed -i 's/#AllowAgentForwarding yes/AllowAgentForwarding yes/g' /etc/ssh/ssh
RUN sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/g' /etc/ssh/sshd_config RUN sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/g' /etc/ssh/sshd_config
RUN sed -i 's/GatewayPorts no/GatewayPorts yes/g' /etc/ssh/sshd_config RUN sed -i 's/GatewayPorts no/GatewayPorts yes/g' /etc/ssh/sshd_config
RUN sed -i 's/X11Forwarding no/X11Forwarding yes/g' /etc/ssh/sshd_config RUN sed -i 's/X11Forwarding no/X11Forwarding yes/g' /etc/ssh/sshd_config
# docker build -t sshd .
# docker run --rm -it -e SUDO_ACCESS=true -e PASSWORD_ACCESS=true -e USER_PASSWORD=123456 -p 2222:2222 sshd