More terminal launcher rework

This commit is contained in:
crschnick 2024-08-13 14:48:56 +00:00
parent 20206b6263
commit da42eb578f
45 changed files with 443 additions and 20 deletions

View file

@ -65,8 +65,8 @@ dependencies {
api group: 'org.kordamp.ikonli', name: 'ikonli-javafx', version: "12.2.0"
api group: 'org.kordamp.ikonli', name: 'ikonli-material-pack', version: "12.2.0"
api group: 'org.kordamp.ikonli', name: 'ikonli-feather-pack', version: "12.2.0"
api group: 'org.slf4j', name: 'slf4j-api', version: '2.0.15'
api group: 'org.slf4j', name: 'slf4j-jdk-platform-logging', version: '2.0.15'
api group: 'org.slf4j', name: 'slf4j-api', version: '2.0.16'
api group: 'org.slf4j', name: 'slf4j-jdk-platform-logging', version: '2.0.16'
api 'io.xpipe:modulefs:0.1.5'
api 'net.synedra:validatorfx:0.4.2'
api files("$rootDir/gradle/gradle_scripts/atlantafx-base-2.0.2.jar")

View file

@ -25,7 +25,7 @@ public class SshLaunchExchangeImpl extends SshLaunchExchange {
}
TerminalLauncherManager.submitAsync(UUID.randomUUID(), ((ShellStore) DataStorage.get().local().getStore()).control(),
TerminalInitScriptConfig.ofName("abc"),null);
var r = TerminalLauncherManager.waitForFirstLaunch();
var r = TerminalLauncherManager.waitForNextLaunch();
var c = ProcessControlProvider.get().getEffectiveLocalDialect().getOpenScriptCommand(r.toString()).buildBaseParts(null);
return Response.builder().command(c).build();
}

View file

@ -6,9 +6,9 @@ import io.xpipe.app.util.*;
import io.xpipe.core.process.CommandBuilder;
import io.xpipe.core.process.OsType;
import io.xpipe.core.util.SecretValue;
import lombok.Value;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@ -16,6 +16,14 @@ import java.util.function.Supplier;
public interface ExternalRdpClientType extends PrefsChoiceValue {
public static ExternalRdpClientType getApplicationLauncher() {
if (OsType.getLocal() == OsType.WINDOWS) {
return MSTSC;
} else {
return AppPrefs.get().rdpClientType().getValue();
}
}
ExternalRdpClientType MSTSC = new PathCheckType("app.mstsc", "mstsc.exe", false) {
@Override
@ -62,6 +70,37 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
return cmd.readStdoutOrThrow();
}
};
ExternalRdpClientType DEVOLUTIONS = new WindowsType("app.devolutions", "RemoteDesktopManager") {
@Override
protected Optional<Path> determineInstallation() {
try {
var r = WindowsRegistry.local().readValue(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes\\rdm\\DefaultIcon");
return r.map(Path::of);
} catch (Exception e) {
ErrorEvent.fromThrowable(e).omit().handle();
return Optional.empty();
}
}
@Override
protected void execute(Path file, LaunchConfiguration configuration) throws Exception {
var config = writeConfig(configuration.getConfig());
LocalShell.getShell().executeSimpleCommand(CommandBuilder.of().addFile(file.toString()).addFile(config.toString()).discardOutput());
ThreadHelper.runFailableAsync(() -> {
// Startup is slow
ThreadHelper.sleep(10000);
Files.delete(config);
});
}
@Override
public boolean supportsPasswordPassing() {
return false;
}
};
ExternalRdpClientType REMMINA = new PathCheckType("app.remmina", "remmina", true) {
@Override
@ -96,7 +135,7 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
}
};
ExternalRdpClientType CUSTOM = new CustomType();
List<ExternalRdpClientType> WINDOWS_CLIENTS = List.of(MSTSC);
List<ExternalRdpClientType> WINDOWS_CLIENTS = List.of(MSTSC, DEVOLUTIONS);
List<ExternalRdpClientType> LINUX_CLIENTS = List.of(REMMINA);
List<ExternalRdpClientType> MACOS_CLIENTS = List.of(MICROSOFT_REMOTE_DESKTOP_MACOS_APP);
@ -145,6 +184,29 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
SecretValue password;
}
abstract class WindowsType extends ExternalApplicationType.WindowsType implements ExternalRdpClientType {
public WindowsType(String id, String executable) {
super(id, executable);
}
@Override
public void launch(LaunchConfiguration configuration) throws Exception {
var location = determineFromPath();
if (location.isEmpty()) {
location = determineInstallation();
if (location.isEmpty()) {
throw new IOException("Unable to find installation of "
+ toTranslatedString().getValue());
}
}
execute(location.get(), configuration);
}
protected abstract void execute(Path file, LaunchConfiguration configuration) throws Exception;
}
abstract class PathCheckType extends ExternalApplicationType.PathApplication implements ExternalRdpClientType {
public PathCheckType(String id, String executable, boolean explicityAsync) {

View file

@ -2,6 +2,7 @@ package io.xpipe.app.storage;
import io.xpipe.app.comp.store.StoreSortMode;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.FixedHierarchyStore;
import io.xpipe.app.util.ThreadHelper;
@ -120,9 +121,11 @@ public abstract class DataStorage {
}
public void forceRewrite() {
TrackEvent.info("Starting forced storage rewrite");
getStoreEntries().forEach(dataStoreEntry -> {
dataStoreEntry.reassignStore();
});
TrackEvent.info("Finished forced storage rewrite");
}
private void dispose() {

View file

@ -1,5 +1,9 @@
package io.xpipe.app.terminal;
import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.ext.PrefsChoiceValue;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.prefs.ExternalApplicationType;
@ -8,18 +12,181 @@ import io.xpipe.app.util.*;
import io.xpipe.core.process.*;
import io.xpipe.core.store.FilePath;
import io.xpipe.core.util.FailableFunction;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
import lombok.Getter;
import lombok.Value;
import lombok.With;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
public interface ExternalTerminalType extends PrefsChoiceValue {
// ExternalTerminalType PUTTY = new WindowsType("app.putty","putty") {
//
// @Override
// protected Optional<Path> determineInstallation() {
// try {
// var r = WindowsRegistry.local().readValue(WindowsRegistry.HKEY_LOCAL_MACHINE,
// "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Xshell.exe");
// return r.map(Path::of);
// } catch (Exception e) {
// ErrorEvent.fromThrowable(e).omit().handle();
// return Optional.empty();
// }
// }
//
// @Override
// public boolean supportsTabs() {
// return true;
// }
//
// @Override
// public boolean isRecommended() {
// return false;
// }
//
// @Override
// public boolean supportsColoredTitle() {
// return false;
// }
//
// @Override
// protected void execute(Path file, LaunchConfiguration configuration) throws Exception {
// try (var sc = LocalShell.getShell()) {
// SshLocalBridge.init();
// var b = SshLocalBridge.get();
// var command = CommandBuilder.of().addFile(file.toString()).add("-ssh", "localhost", "-l").addQuoted(b.getUser())
// .add("-i").addFile(b.getIdentityKey().toString()).add("-P", "" + b.getPort()).add("-hostkey").addFile(b.getPubHostKey().toString());
// sc.executeSimpleCommand(command);
// }
// }
// };
ExternalTerminalType XSHELL = new WindowsType("app.xShell","Xshell") {
@Override
protected Optional<Path> determineInstallation() {
try {
var r = WindowsRegistry.local().readValue(WindowsRegistry.HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Xshell.exe");
return r.map(Path::of);
} catch (Exception e) {
ErrorEvent.fromThrowable(e).omit().handle();
return Optional.empty();
}
}
@Override
public boolean supportsTabs() {
return true;
}
@Override
public boolean isRecommended() {
return false;
}
@Override
public boolean supportsColoredTitle() {
return false;
}
@Override
protected void execute(Path file, LaunchConfiguration configuration) throws Exception {
SshLocalBridge.init();
if (!showInfo()) {
return;
}
try (var sc = LocalShell.getShell()) {
var b = SshLocalBridge.get();
var command = CommandBuilder.of().addFile(file.toString()).add("-url").addQuoted("ssh://" + b.getUser() + "@localhost:" + b.getPort())
.add("-i", "xpipe_bridge");
sc.executeSimpleCommand(command);
}
}
private boolean showInfo() {
boolean set = AppCache.get("xshellSetup", Boolean.class, () -> false);
if (set) {
return true;
}
var b = SshLocalBridge.get();
var r = AppWindowHelper.showBlockingAlert(
alert -> {
alert.setTitle(AppI18n.get("xshellSetup"));
alert.setAlertType(Alert.AlertType.NONE);
var activated = AppI18n.get().getMarkdownDocumentation("app:xshellSetup");
var markdown = new MarkdownComp(activated, s -> s.formatted(b.getIdentityKey(), "xpipe_bridge"))
.prefWidth(450)
.prefHeight(400)
.createRegion();
alert.getDialogPane().setContent(markdown);
alert.getButtonTypes().add(new ButtonType(AppI18n.get("ok"), ButtonBar.ButtonData.OK_DONE));
});
r.filter(buttonType -> buttonType.getButtonData().isDefaultButton());
r.ifPresent(buttonType -> {
AppCache.update("xshellSetup", true);
});
return r.isPresent();
}
};
ExternalTerminalType SECURECRT = new WindowsType("app.secureCrt","SecureCRT") {
@Override
protected Optional<Path> determineInstallation() {
try (var sc = LocalShell.getShell().start()) {
var env = sc.executeSimpleStringCommand(
sc.getShellDialect().getPrintEnvironmentVariableCommand("ProgramFiles"));
var file = Path.of(env, "VanDyke Software\\SecureCRT\\SecureCRT.exe");
if (!Files.exists(file)) {
return Optional.empty();
}
return Optional.of(file);
} catch (Exception e) {
ErrorEvent.fromThrowable(e).omit().handle();
return Optional.empty();
}
}
@Override
public boolean supportsTabs() {
return true;
}
@Override
public boolean isRecommended() {
return false;
}
@Override
public boolean supportsColoredTitle() {
return false;
}
@Override
protected void execute(Path file, LaunchConfiguration configuration) throws Exception {
try (var sc = LocalShell.getShell()) {
SshLocalBridge.init();
var b = SshLocalBridge.get();
var command = CommandBuilder.of().addFile(file.toString()).add("/T").add("/SSH2", "/ACCEPTHOSTKEYS", "/I").addFile(
b.getIdentityKey().toString()).add("/P", "" + b.getPort()).add("/L").addQuoted(b.getUser()).add("localhost");
sc.executeSimpleCommand(command);
}
}
};
ExternalTerminalType MOBAXTERM = new WindowsType("app.mobaXterm","MobaXterm") {
@Override
@ -108,12 +275,44 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
@Override
public void launch(LaunchConfiguration configuration) throws Exception {
SshLocalBridge.init();
if (!showInfo()) {
return;
}
var name = "xpipe_bridge";
var host = "localhost";
var port = 21722;
var user = System.getProperty("user.name");
var port = SshLocalBridge.get().getPort();
var user = SshLocalBridge.get().getUser();
Hyperlinks.open("termius://app/host-sharing#label=" + name + "&ip=" + host + "&port=" + port + "&username="
+ user + "&os=windows");
+ user + "&os=undefined");
}
private boolean showInfo() {
boolean set = AppCache.get("termiusSetup", Boolean.class, () -> false);
if (set) {
return true;
}
var b = SshLocalBridge.get();
var r = AppWindowHelper.showBlockingAlert(
alert -> {
alert.setTitle(AppI18n.get("termiusSetup"));
alert.setAlertType(Alert.AlertType.NONE);
var activated = AppI18n.get().getMarkdownDocumentation("app:termiusSetup");
var markdown = new MarkdownComp(activated, s -> s.formatted(b.getIdentityKey(), "xpipe_bridge"))
.prefWidth(450)
.prefHeight(400)
.createRegion();
alert.getDialogPane().setContent(markdown);
alert.getButtonTypes().add(new ButtonType(AppI18n.get("ok"), ButtonBar.ButtonData.OK_DONE));
});
r.filter(buttonType -> buttonType.getButtonData().isDefaultButton());
r.ifPresent(buttonType -> {
AppCache.update("termiusSetup", true);
});
return r.isPresent();
}
};
@ -747,8 +946,10 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
TabbyTerminalType.TABBY_WINDOWS,
AlacrittyTerminalType.ALACRITTY_WINDOWS,
WezTerminalType.WEZTERM_WINDOWS,
TERMIUS,
MOBAXTERM,
SECURECRT,
TERMIUS,
XSHELL,
CMD,
PWSH,
POWERSHELL);

View file

@ -20,6 +20,10 @@ public class SshLocalBridge {
private static SshLocalBridge INSTANCE;
public static SshLocalBridge get() {
return INSTANCE;
}
private final Path directory;
private final int port;
private final String user;
@ -33,19 +37,19 @@ public class SshLocalBridge {
}
public Path getPubHostKey() {
return directory.resolve("host_key.pub");
return directory.resolve("xpipe_bridge_host_key.pub");
}
public Path getHostKey() {
return directory.resolve("host_key");
return directory.resolve("xpipe_bridge_host_key");
}
public Path getPubIdentityKey() {
return directory.resolve("identity.pub");
return directory.resolve("xpipe_bridge.pub");
}
public Path getIdentityKey() {
return directory.resolve("identity");
return directory.resolve("xpipe_bridge");
}
public Path getConfig() {
@ -66,12 +70,15 @@ public class SshLocalBridge {
var hostKey = INSTANCE.getHostKey();
if (!sc.getShellDialect().createFileExistsCommand(sc, hostKey.toString()).executeAndCheck()) {
sc.executeSimpleCommand("ssh-keygen -q -N \"\" -t ed25519 -f \"" + hostKey + "\"");
sc.command(CommandBuilder.of().add("ssh-keygen", "-q", "-N")
.addQuoted("").add("-C").addQuoted("XPipe SSH bridge host key")
.add("-t", "ed25519", "-f").addFile(hostKey.toString())).execute();
}
var idKey = INSTANCE.getIdentityKey();
if (!sc.getShellDialect().createFileExistsCommand(sc, idKey.toString()).executeAndCheck()) {
sc.executeSimpleCommand("ssh-keygen -q -N \"\" -t ed25519 -f \"" + idKey + "\"");
sc.command(CommandBuilder.of().add("ssh-keygen", "-q", "-N")
.addQuoted("").add("-C").addQuoted("XPipe SSH bridge identity").add("-t", "ed25519", "-f").addFile(idKey.toString())).execute();
}
var config = INSTANCE.getConfig();
@ -92,7 +99,7 @@ public class SshLocalBridge {
.formatted(command, pidFile.toString(), "" + port, INSTANCE.getHostKey().toString(), INSTANCE.getPubIdentityKey());;
Files.writeString(config, content);
INSTANCE.updateConfig();
// INSTANCE.updateConfig();
var exec = getSshd(sc);
var launchCommand = CommandBuilder.of().addFile(exec).add("-f").addFile(INSTANCE.getConfig().toString()).add("-p", "" + port);

View file

@ -72,12 +72,13 @@ public class TerminalLauncherManager {
return latch;
}
public static Path waitForFirstLaunch() throws BeaconClientException, BeaconServerException {
public static Path waitForNextLaunch() throws BeaconClientException, BeaconServerException {
if (entries.isEmpty()) {
throw new BeaconClientException("Unknown launch request");
}
var first = entries.firstEntry();
entries.remove(first.getKey());
return waitForCompletion(first.getKey());
}
@ -94,8 +95,8 @@ public class TerminalLauncherManager {
}
var r = e.getResult();
entries.remove(request);
if (r instanceof ResultFailure failure) {
entries.remove(request);
var t = failure.getThrowable();
throw new BeaconServerException(t);
}

View file

@ -1,4 +1,4 @@
name=SLF4J
version=2.0.15
version=2.0.16
license=MIT License
link=https://www.slf4j.org/

View file

@ -61,3 +61,8 @@ dashlane=Dashlane
lastpass=LastPass
macosKeychain=macOS keychain
windowsTerminalCanary=Windows Terminal Canary
secureCrt=SecureCRT
xShell=Xshell
mobaXterm=MobaXterm
termius=Termius
devolutions=Devolutions

View file

@ -503,3 +503,5 @@ workspaceCreationAlertTitle=Oprettelse af arbejdsområde
developerForceSshTty=Fremtving SSH TTY
developerForceSshTtyDescription=Få alle SSH-forbindelser til at tildele en pty for at teste understøttelsen af en manglende stderr og en pty.
ttyWarning=Forbindelsen har tvangstildelt en pty/tty og giver ikke en separat stderr-strøm.\n\nDet kan føre til et par problemer.\n\nHvis du kan, så prøv at få forbindelseskommandoen til ikke at tildele en pty.
xshellSetup=Xshell-opsætning
termiusSetup=Termius-opsætning

View file

@ -497,3 +497,5 @@ workspaceCreationAlertTitle=Arbeitsbereich erstellen
developerForceSshTty=SSH TTY erzwingen
developerForceSshTtyDescription=Lass alle SSH-Verbindungen ein pty zuweisen, um die Unterstützung für einen fehlenden stderr und ein pty zu testen.
ttyWarning=Die Verbindung hat zwangsweise ein pty/tty zugewiesen und stellt keinen separaten stderr-Stream zur Verfügung.\n\nDas kann zu einigen Problemen führen.\n\nWenn du kannst, solltest du dafür sorgen, dass der Verbindungsbefehl kein pty zuweist.
xshellSetup=Xshell-Einrichtung
termiusSetup=Termius Einrichtung

View file

@ -501,3 +501,5 @@ workspaceCreationAlertTitle=Workspace creation
developerForceSshTty=Force SSH TTY
developerForceSshTtyDescription=Make all SSH connections allocate a pty to test the support for a missing stderr and a pty.
ttyWarning=The connection has forcefully allocated a pty/tty and does not provide a separate stderr stream.\n\nThis might lead to a few problems.\n\nIf you can, look into making the connection command not allocate a pty.
xshellSetup=Xshell setup
termiusSetup=Termius setup

View file

@ -484,3 +484,5 @@ workspaceCreationAlertTitle=Creación de espacios de trabajo
developerForceSshTty=Forzar SSH TTY
developerForceSshTtyDescription=Haz que todas las conexiones SSH asignen una pty para probar la compatibilidad con una stderr y una pty ausentes.
ttyWarning=La conexión ha asignado forzosamente un pty/tty y no proporciona un flujo stderr separado.\n\nEsto puede provocar algunos problemas.\n\nSi puedes, intenta que el comando de conexión no asigne una pty.
xshellSetup=Configuración de Xshell
termiusSetup=Configuración de Termius

View file

@ -484,3 +484,5 @@ workspaceCreationAlertTitle=Création d'un espace de travail
developerForceSshTty=Force SSH TTY
developerForceSshTtyDescription=Fais en sorte que toutes les connexions SSH allouent un pty pour tester la prise en charge d'un stderr et d'un pty manquants.
ttyWarning=La connexion a alloué de force un pty/tty et ne fournit pas de flux stderr séparé.\n\nCela peut entraîner quelques problèmes.\n\nSi tu le peux, essaie de faire en sorte que la commande de connexion n'alloue pas de pty.
xshellSetup=Configuration de Xshell
termiusSetup=Installation de Termius

View file

@ -484,3 +484,5 @@ workspaceCreationAlertTitle=Creazione di uno spazio di lavoro
developerForceSshTty=Forza SSH TTY
developerForceSshTtyDescription=Fai in modo che tutte le connessioni SSH allocino una pty per testare il supporto di una stderr e di una pty mancanti.
ttyWarning=La connessione ha allocato forzatamente una pty/tty e non fornisce un flusso stderr separato.\n\nQuesto potrebbe causare alcuni problemi.\n\nSe puoi, cerca di fare in modo che il comando di connessione non allarghi una pty.
xshellSetup=Configurazione di Xshell
termiusSetup=Configurazione di Termius

View file

@ -484,3 +484,5 @@ workspaceCreationAlertTitle=ワークスペースの作成
developerForceSshTty=強制SSH TTY
developerForceSshTtyDescription=すべてのSSHコネクションにptyを割り当て、stderrとptyがない場合のサポートをテストする。
ttyWarning=接続が強制的にpty/ttyを割り当て、個別のstderrストリームを提供しない。\n\nこれはいくつかの問題を引き起こす可能性がある。\n\n可能であれば、接続コマンドで pty を割り当てないようにすることを検討してほしい。
xshellSetup=Xshellのセットアップ
termiusSetup=テルミウスのセットアップ

View file

@ -484,3 +484,5 @@ workspaceCreationAlertTitle=Werkruimte maken
developerForceSshTty=SSH TTY afdwingen
developerForceSshTtyDescription=Laat alle SSH-verbindingen een pty toewijzen om de ondersteuning voor een ontbrekende stderr en een pty te testen.
ttyWarning=De verbinding heeft geforceerd een pty/tty toegewezen en biedt geen aparte stderr stream.\n\nDit kan tot een paar problemen leiden.\n\nAls je kunt, kijk dan of je het connection commando geen pty kunt laten toewijzen.
xshellSetup=Xshell installatie
termiusSetup=Termius installatie

View file

@ -484,3 +484,5 @@ workspaceCreationAlertTitle=Criação de espaço de trabalho
developerForceSshTty=Força o SSH TTY
developerForceSshTtyDescription=Faz com que todas as ligações SSH atribuam um pty para testar o suporte para um stderr e um pty em falta.
ttyWarning=A ligação atribuiu à força um pty/tty e não fornece um fluxo stderr separado.\n\nIsto pode levar a alguns problemas.\n\nSe puderes, tenta fazer com que o comando de ligação não atribua um pty.
xshellSetup=Configuração do Xshell
termiusSetup=Configuração do Termius

View file

@ -484,3 +484,5 @@ workspaceCreationAlertTitle=Создание рабочего пространс
developerForceSshTty=Принудительный SSH TTY
developerForceSshTtyDescription=Заставь все SSH-соединения выделять pty, чтобы проверить поддержку отсутствующего stderr и pty.
ttyWarning=Соединение принудительно выделило pty/tty и не предоставляет отдельный поток stderr.\n\nЭто может привести к нескольким проблемам.\n\nЕсли можешь, попробуй сделать так, чтобы команда подключения не выделяла pty.
xshellSetup=Настройка Xshell
termiusSetup=Настройка Термиуса

View file

@ -485,3 +485,5 @@ workspaceCreationAlertTitle=Çalışma alanı oluşturma
developerForceSshTty=SSH TTY'yi Zorla
developerForceSshTtyDescription=Eksik bir stderr ve bir pty desteğini test etmek için tüm SSH bağlantılarının bir pty ayırmasını sağlayın.
ttyWarning=Bağlantı zorla bir pty/tty ayırmış ve ayrı bir stderr akışı sağlamıyor.\n\nBu durum birkaç soruna yol açabilir.\n\nEğer yapabiliyorsanız, bağlantı komutunun bir pty tahsis etmemesini sağlayın.
xshellSetup=Xshell kurulumu
termiusSetup=Termius kurulumu

View file

@ -484,3 +484,5 @@ workspaceCreationAlertTitle=创建工作区
developerForceSshTty=强制 SSH TTY
developerForceSshTtyDescription=让所有 SSH 连接都分配一个 pty以测试对缺失的 stderr 和 pty 的支持。
ttyWarning=连接强行分配了 pty/tty且未提供单独的 stderr 流。\n\n这可能会导致一些问题。\n\n如果可以请考虑让连接命令不分配 pty。
xshellSetup=Xshell 设置
termiusSetup=Termius 设置

View file

@ -0,0 +1,5 @@
# Termius setup
For at bruge Termius som din terminal kan du forbinde den til XPipe SSH-broen. Det kan ske automatisk, når den lokale ssh-nøgle til broen er blevet tilføjet til Termius.
Det eneste, du skal gøre manuelt, er at tilføje den private nøglefil `%s` til Termius først.

View file

@ -0,0 +1,5 @@
# Termius setup
Um Termius als Terminal zu verwenden, kannst du ihn mit der XPipe SSH-Bridge verbinden. Das kann automatisch funktionieren, sobald der lokale Bridge-Ssh-Schlüssel zu Termius hinzugefügt wurde.
Das Einzige, was du manuell tun musst, ist, die private Schlüsseldatei `%s` zuerst zu Termius hinzuzufügen.

View file

@ -0,0 +1,5 @@
# Termius setup
To use Termius as your terminal, you can connect it to the XPipe SSH bridge. This can work automatically once the local bridge ssh key has been added to Termius.
The only thing you have to do manually is to add the private key file `%s` to Termius first.

View file

@ -0,0 +1,5 @@
# Configuración de Termius
Para utilizar Termius como terminal, puedes conectarlo al puente SSH de XPipe. Esto puede funcionar automáticamente una vez que se haya añadido a Termius la clave ssh del puente local.
Lo único que tienes que hacer manualmente es añadir primero el archivo de clave privada `%s` a Termius.

View file

@ -0,0 +1,5 @@
# Installation de Termius
Pour utiliser Termius comme terminal, tu peux le connecter au pont SSH de XPipe. Cela peut fonctionner automatiquement une fois que la clé ssh du pont local a été ajoutée à Termius.
La seule chose que tu dois faire manuellement est d'ajouter le fichier de clé privée `%s` à Termius d'abord.

View file

@ -0,0 +1,5 @@
# Configurazione di Termius
Per utilizzare Termius come terminale, puoi collegarlo al bridge SSH di XPipe. Questo può funzionare automaticamente una volta che la chiave ssh del bridge locale è stata aggiunta a Termius.
L'unica cosa che devi fare manualmente è aggiungere il file della chiave privata `%s` a Termius.

View file

@ -0,0 +1,5 @@
# テルミウスのセットアップ
Termiusをターミナルとして使用するには、XPipe SSHブリッジに接続する。ローカルブリッジのsshキーがTermiusに追加されれば自動的に動作する。
唯一手動で行う必要があるのは、最初に秘密鍵ファイル`%s`をTermiusに追加することだ。

View file

@ -0,0 +1,5 @@
# Termius installatie
Om Termius als terminal te gebruiken, kun je het verbinden met de XPipe SSH bridge. Dit kan automatisch werken zodra de lokale bridge ssh sleutel is toegevoegd aan Termius.
Het enige dat je handmatig moet doen is eerst het private key bestand `%s` toevoegen aan Termius.

View file

@ -0,0 +1,5 @@
# Configuração do Termius
Para usar o Termius como terminal, podes ligá-lo à bridge SSH XPipe. Isto pode funcionar automaticamente uma vez que a chave ssh da ponte local tenha sido adicionada ao Termius.
A única coisa que tens de fazer manualmente é adicionar o ficheiro de chave privada `%s` ao Termius primeiro.

View file

@ -0,0 +1,5 @@
# Настройка Термиуса
Чтобы использовать Termius в качестве терминала, ты можешь подключить его к SSH-мосту XPipe. Это может работать автоматически, как только локальный ssh-ключ моста будет добавлен в Termius.
Единственное, что тебе придется сделать вручную, - это сначала добавить в Termius файл закрытого ключа `%s`.

View file

@ -0,0 +1,5 @@
# Termius kurulumu
Termius'u terminaliniz olarak kullanmak için XPipe SSH köprüsüne bağlayabilirsiniz. Yerel köprü ssh anahtarı Termius'a eklendiğinde bu otomatik olarak çalışabilir.
Manuel olarak yapmanız gereken tek şey, önce `%s` özel anahtar dosyasını Termius'a eklemektir.

View file

@ -0,0 +1,5 @@
# Termius 设置
要将 Termius 作为终端使用,可以将其连接到 XPipe SSH 网桥。一旦本地网桥的 ssh 密钥添加到 Termius它就会自动运行。
唯一需要手动操作的是先将私钥文件 `%s` 添加到 Termius。

View file

@ -0,0 +1,5 @@
# Xshell setup
For at bruge Xshell som din terminal kan du forbinde den til XPipe SSH-broen. Det kan ske automatisk, når den lokale ssh-nøgle til broen er blevet føjet til Xshell med det korrekte navn.
Det eneste, du skal gøre manuelt, er at tilføje den private nøglefil `%s` til Xshell med det faste navn `%s`.

View file

@ -0,0 +1,5 @@
# Xshell-Einrichtung
Um Xshell als Terminal zu verwenden, kannst du es mit der XPipe SSH-Bridge verbinden. Das kann automatisch funktionieren, sobald der lokale Bridge-Ssh-Schlüssel mit dem richtigen Namen zu Xshell hinzugefügt wurde.
Das Einzige, was du manuell tun musst, ist, die private Schlüsseldatei `%s` mit dem festen Namen `%s` zu Xshell hinzuzufügen.

View file

@ -0,0 +1,5 @@
# Xshell setup
To use Xshell as your terminal, you can connect it to the XPipe SSH bridge. This can work automatically once the local bridge ssh key has been added to Xshell with the correct name.
The only thing you have to do manually is to add the private key file `%s` to Xshell with the fixed name `%s`.

View file

@ -0,0 +1,5 @@
# Configuración de Xshell
Para utilizar Xshell como terminal, puedes conectarlo al puente SSH de XPipe. Esto puede funcionar automáticamente una vez que la clave ssh del puente local se haya añadido a Xshell con el nombre correcto.
Lo único que tienes que hacer manualmente es añadir el archivo de clave privada `%s` a Xshell con el nombre fijo `%s`.

View file

@ -0,0 +1,5 @@
# Configuration de Xshell
Pour utiliser Xshell comme terminal, tu peux le connecter au pont SSH de XPipe. Cela peut fonctionner automatiquement une fois que la clé ssh du pont local a été ajoutée à Xshell avec le nom correct.
La seule chose que tu dois faire manuellement est d'ajouter le fichier de clé privée `%s` à Xshell avec le nom fixe `%s`.

View file

@ -0,0 +1,5 @@
# Configurazione di Xshell
Per utilizzare Xshell come terminale, puoi collegarlo al bridge SSH di XPipe. Questo può funzionare automaticamente una volta che la chiave ssh del bridge locale è stata aggiunta a Xshell con il nome corretto.
L'unica cosa che devi fare manualmente è aggiungere il file della chiave privata `%s` a Xshell con il nome fisso `%s`.

View file

@ -0,0 +1,5 @@
# Xshellのセットアップ
Xshellをターミナルとして使用するには、XPipe SSHブリッジに接続する。ローカルブリッジのsshキーが正しい名前でXshellに追加されれば、自動的に動作する。
手動で行う必要があるのは、秘密鍵ファイル`%s`を固定名`%s`でXshellに追加することだけだ。

View file

@ -0,0 +1,5 @@
# Xshell instelling
Om Xshell als terminal te gebruiken kun je het verbinden met de XPipe SSH bridge. Dit kan automatisch werken zodra de lokale bridge ssh key is toegevoegd aan Xshell met de juiste naam.
Het enige dat je handmatig moet doen is het private key bestand `%s` toevoegen aan Xshell met de vaste naam `%s`.

View file

@ -0,0 +1,5 @@
# Configuração do Xshell
Para utilizar o Xshell como o teu terminal, podes ligá-lo à ponte SSH XPipe. Isto pode funcionar automaticamente quando a chave ssh da ponte local tiver sido adicionada ao Xshell com o nome correto.
A única coisa que tens de fazer manualmente é adicionar o ficheiro de chave privada `%s` ao Xshell com o nome fixo `%s`.

View file

@ -0,0 +1,5 @@
# Xshell setup
Чтобы использовать Xshell в качестве терминала, ты можешь подключить его к SSH-мосту XPipe. Это может работать автоматически, как только локальный ssh-ключ моста будет добавлен в Xshell с правильным именем.
Единственное, что тебе придется сделать вручную, - это добавить файл закрытого ключа `%s` в Xshell с фиксированным именем `%s`.

View file

@ -0,0 +1,5 @@
# Xshell kurulumu
Xshell'i terminaliniz olarak kullanmak için XPipe SSH köprüsüne bağlayabilirsiniz. Yerel köprü ssh anahtarı Xshell'e doğru isimle eklendiğinde bu otomatik olarak çalışabilir.
Manuel olarak yapmanız gereken tek şey `%s` özel anahtar dosyasını `%s` sabit adıyla Xshell'e eklemektir.

View file

@ -0,0 +1,5 @@
# Xshell 设置
要将 Xshell 用作终端,可以将其连接到 XPipe SSH 网桥。一旦本地桥接器的 ssh 密钥以正确的名称添加到 Xshell它就会自动运行。
唯一需要手动操作的是将私钥文件 `%s` 添加到 Xshell并使用固定名称 `%s`