This commit is contained in:
crschnick 2024-11-14 15:24:57 +00:00
parent 9248c38c8f
commit 191cd49b29
26 changed files with 162 additions and 97 deletions

View file

@ -279,12 +279,11 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
var cc = fileSystem var cc = fileSystem
.getShell() .getShell()
.get() .get()
.singularSubShell( .singularSubShell(ShellOpenFunction.of(CommandBuilder.ofString(adjustedPath), false));
ShellOpenFunction.of(CommandBuilder.ofString(adjustedPath), false)); openTerminalAsync(name, directory, cc, true);
openTerminalAsync(name,directory,cc, true);
} else { } else {
var cc = fileSystem.getShell().get().command(adjustedPath); var cc = fileSystem.getShell().get().command(adjustedPath);
openTerminalAsync(name,directory,cc, true); openTerminalAsync(name, directory, cc, true);
} }
}); });
return Optional.ofNullable(currentPath.get()); return Optional.ofNullable(currentPath.get());
@ -539,7 +538,8 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
history.updateCurrent(null); history.updateCurrent(null);
} }
public void openTerminalAsync(String name, String directory, ProcessControl processControl, boolean dockIfPossible) { public void openTerminalAsync(
String name, String directory, ProcessControl processControl, boolean dockIfPossible) {
ThreadHelper.runFailableAsync(() -> { ThreadHelper.runFailableAsync(() -> {
if (fileSystem == null) { if (fileSystem == null) {
return; return;
@ -550,9 +550,11 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
var dock = shouldLaunchSplitTerminal() && dockIfPossible; var dock = shouldLaunchSplitTerminal() && dockIfPossible;
var uuid = UUID.randomUUID(); var uuid = UUID.randomUUID();
terminalRequests.add(uuid); terminalRequests.add(uuid);
if (dock && browserModel instanceof BrowserFullSessionModel fullSessionModel && if (dock
!(fullSessionModel.getSplits().get(this) instanceof BrowserTerminalDockTabModel)) { && browserModel instanceof BrowserFullSessionModel fullSessionModel
fullSessionModel.splitTab(this, new BrowserTerminalDockTabModel(browserModel, this, terminalRequests)); && !(fullSessionModel.getSplits().get(this) instanceof BrowserTerminalDockTabModel)) {
fullSessionModel.splitTab(
this, new BrowserTerminalDockTabModel(browserModel, this, terminalRequests));
} }
TerminalLauncher.open(entry.getEntry(), name, directory, processControl, uuid, !dock); TerminalLauncher.open(entry.getEntry(), name, directory, processControl, uuid, !dock);

View file

@ -16,7 +16,6 @@ import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableBooleanValue; import javafx.beans.value.ObservableBooleanValue;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import java.util.ArrayList;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@ -57,7 +56,9 @@ public final class BrowserTerminalDockTabModel extends BrowserSessionTab {
} }
var sessions = TerminalView.get().getSessions(); var sessions = TerminalView.get().getSessions();
var tv = sessions.stream().filter(s -> terminalRequests.contains(s.getRequest()) && s.getTerminal().isRunning()) var tv = sessions.stream()
.filter(s -> terminalRequests.contains(s.getRequest())
&& s.getTerminal().isRunning())
.map(s -> s.getTerminal().controllable()) .map(s -> s.getTerminal().controllable())
.flatMap(Optional::stream) .flatMap(Optional::stream)
.toList(); .toList();
@ -72,7 +73,10 @@ public final class BrowserTerminalDockTabModel extends BrowserSessionTab {
@Override @Override
public void onTerminalClosed(TerminalView.TerminalSession instance) { public void onTerminalClosed(TerminalView.TerminalSession instance) {
var sessions = TerminalView.get().getSessions(); var sessions = TerminalView.get().getSessions();
var remaining = sessions.stream().filter(s -> terminalRequests.contains(s.getRequest()) && s.getTerminal().isRunning()).toList(); var remaining = sessions.stream()
.filter(s -> terminalRequests.contains(s.getRequest())
&& s.getTerminal().isRunning())
.toList();
if (remaining.isEmpty()) { if (remaining.isEmpty()) {
((BrowserFullSessionModel) browserModel).unsplitTab(BrowserTerminalDockTabModel.this); ((BrowserFullSessionModel) browserModel).unsplitTab(BrowserTerminalDockTabModel.this);
} }

View file

@ -88,7 +88,10 @@ public class ModifiedStage extends Stage {
NativeWinWindowControl.DmwaWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE.get(), NativeWinWindowControl.DmwaWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE.get(),
AppPrefs.get().theme.getValue().isDark()); AppPrefs.get().theme.getValue().isDark());
boolean seamlessFrame; boolean seamlessFrame;
if (AppPrefs.get().performanceMode().get() || !mergeFrame() || AppMainWindow.getInstance() == null || stage != AppMainWindow.getInstance().getStage()) { if (AppPrefs.get().performanceMode().get()
|| !mergeFrame()
|| AppMainWindow.getInstance() == null
|| stage != AppMainWindow.getInstance().getStage()) {
seamlessFrame = false; seamlessFrame = false;
} else { } else {
seamlessFrame = ctrl.setWindowBackdrop(NativeWinWindowControl.DwmSystemBackDropType.MICA_ALT); seamlessFrame = ctrl.setWindowBackdrop(NativeWinWindowControl.DwmSystemBackDropType.MICA_ALT);

View file

@ -19,8 +19,6 @@ import lombok.SneakyThrows;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
@Getter @Getter
@EqualsAndHashCode @EqualsAndHashCode

View file

@ -3,7 +3,6 @@ package io.xpipe.app.issue;
import io.xpipe.app.core.*; import io.xpipe.app.core.*;
import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.core.window.AppWindowHelper; import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.update.XPipeDistributionType; import io.xpipe.app.update.XPipeDistributionType;
import io.xpipe.app.util.Hyperlinks; import io.xpipe.app.util.Hyperlinks;
import io.xpipe.app.util.ThreadHelper; import io.xpipe.app.util.ThreadHelper;
@ -74,10 +73,7 @@ public class TerminalErrorHandler extends GuiErrorHandlerBase implements ErrorHa
} }
try { try {
var rel = XPipeDistributionType.get() var rel = XPipeDistributionType.get().getUpdateHandler().refreshUpdateCheck(false, false);
.getUpdateHandler()
.refreshUpdateCheck(
false, false);
if (rel != null && rel.isUpdate()) { if (rel != null && rel.isUpdate()) {
var update = AppWindowHelper.showBlockingAlert(alert -> { var update = AppWindowHelper.showBlockingAlert(alert -> {
alert.setAlertType(Alert.AlertType.INFORMATION); alert.setAlertType(Alert.AlertType.INFORMATION);

View file

@ -126,7 +126,10 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
// Note for later: When debugging konsole launches, it will always open as a child process of // Note for later: When debugging konsole launches, it will always open as a child process of
// IntelliJ/XPipe even though we try to detach it. // IntelliJ/XPipe even though we try to detach it.
// This is not the case for production where it works as expected // This is not the case for production where it works as expected
return CommandBuilder.of().addIf(configuration.isPreferTabs(), "--new-tab").add("-e").addFile(configuration.getScriptFile()); return CommandBuilder.of()
.addIf(configuration.isPreferTabs(), "--new-tab")
.add("-e")
.addFile(configuration.getScriptFile());
} }
}; };
ExternalTerminalType XFCE = new SimplePathType("app.xfce", "xfce4-terminal", true) { ExternalTerminalType XFCE = new SimplePathType("app.xfce", "xfce4-terminal", true) {
@ -153,7 +156,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
@Override @Override
protected CommandBuilder toCommand(TerminalLaunchConfiguration configuration) { protected CommandBuilder toCommand(TerminalLaunchConfiguration configuration) {
return CommandBuilder.of() return CommandBuilder.of()
.addIf(configuration.isPreferTabs(),"--tab") .addIf(configuration.isPreferTabs(), "--tab")
.add("--title") .add("--title")
.addQuoted(configuration.getColoredTitle()) .addQuoted(configuration.getColoredTitle())
.add("--command") .add("--command")
@ -213,7 +216,10 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
@Override @Override
protected CommandBuilder toCommand(TerminalLaunchConfiguration configuration) { protected CommandBuilder toCommand(TerminalLaunchConfiguration configuration) {
return CommandBuilder.of().addIf(configuration.isPreferTabs(), "--new-tab").add("-e").addFile(configuration.getScriptFile()); return CommandBuilder.of()
.addIf(configuration.isPreferTabs(), "--new-tab")
.add("-e")
.addFile(configuration.getScriptFile());
} }
}; };
ExternalTerminalType TILIX = new SimplePathType("app.tilix", "tilix", true) { ExternalTerminalType TILIX = new SimplePathType("app.tilix", "tilix", true) {
@ -642,7 +648,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
default void launch(TerminalLaunchConfiguration configuration) throws Exception {} default void launch(TerminalLaunchConfiguration configuration) throws Exception {}
default FailableFunction<TerminalLaunchConfiguration, String, Exception> remoteLaunchCommand(ShellDialect systemDialect) { default FailableFunction<TerminalLaunchConfiguration, String, Exception> remoteLaunchCommand(
ShellDialect systemDialect) {
return null; return null;
} }
@ -713,5 +720,4 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
protected abstract CommandBuilder toCommand(TerminalLaunchConfiguration configuration) throws Exception; protected abstract CommandBuilder toCommand(TerminalLaunchConfiguration configuration) throws Exception;
} }
} }

View file

@ -51,7 +51,8 @@ public class GnomeTerminalType extends ExternalTerminalType.PathCheckType implem
} }
@Override @Override
public FailableFunction<TerminalLaunchConfiguration, String, Exception> remoteLaunchCommand(ShellDialect systemDialect) { public FailableFunction<TerminalLaunchConfiguration, String, Exception> remoteLaunchCommand(
ShellDialect systemDialect) {
return launchConfiguration -> { return launchConfiguration -> {
var toExecute = CommandBuilder.of() var toExecute = CommandBuilder.of()
.add(executable, "-v", "--title") .add(executable, "-v", "--title")

View file

@ -27,8 +27,7 @@ public interface KittyTerminalType extends ExternalTerminalType, TrackableTermin
} }
} }
private static void open(TerminalLaunchConfiguration configuration, CommandBuilder socketWrite) private static void open(TerminalLaunchConfiguration configuration, CommandBuilder socketWrite) throws Exception {
throws Exception {
try (var sc = LocalShell.getShell().start()) { try (var sc = LocalShell.getShell().start()) {
var payload = JsonNodeFactory.instance.objectNode(); var payload = JsonNodeFactory.instance.objectNode();
var args = configuration.getDialectLaunchCommand().buildBaseParts(sc); var args = configuration.getDialectLaunchCommand().buildBaseParts(sc);

View file

@ -13,7 +13,9 @@ import java.util.Optional;
public class MobaXTermTerminalType extends ExternalTerminalType.WindowsType { public class MobaXTermTerminalType extends ExternalTerminalType.WindowsType {
public MobaXTermTerminalType() {super("app.mobaXterm", "MobaXterm");} public MobaXTermTerminalType() {
super("app.mobaXterm", "MobaXterm");
}
@Override @Override
public TerminalOpenFormat getOpenFormat() { public TerminalOpenFormat getOpenFormat() {
@ -23,7 +25,8 @@ public class MobaXTermTerminalType extends ExternalTerminalType.WindowsType {
@Override @Override
protected Optional<Path> determineInstallation() { protected Optional<Path> determineInstallation() {
try { try {
var r = WindowsRegistry.local().readValue(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes\\mobaxterm\\DefaultIcon"); var r = WindowsRegistry.local()
.readValue(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes\\mobaxterm\\DefaultIcon");
return r.map(Path::of); return r.map(Path::of);
} catch (Exception e) { } catch (Exception e) {
ErrorEvent.fromThrowable(e).omit().handle(); ErrorEvent.fromThrowable(e).omit().handle();
@ -51,14 +54,23 @@ public class MobaXTermTerminalType extends ExternalTerminalType.WindowsType {
try (var sc = LocalShell.getShell()) { try (var sc = LocalShell.getShell()) {
SshLocalBridge.init(); SshLocalBridge.init();
var b = SshLocalBridge.get(); var b = SshLocalBridge.get();
var command = CommandBuilder.of().addFile("ssh").addQuoted(b.getUser() + "@localhost").add("-i").add( var command = CommandBuilder.of()
"\"$(cygpath \"" + b.getIdentityKey().toString() + "\")\"").add("-p").add("" + b.getPort()); .addFile("ssh")
.addQuoted(b.getUser() + "@localhost")
.add("-i")
.add("\"$(cygpath \"" + b.getIdentityKey().toString() + "\")\"")
.add("-p")
.add("" + b.getPort());
// Don't use local shell to build as it uses cygwin // Don't use local shell to build as it uses cygwin
var rawCommand = command.buildSimple(); var rawCommand = command.buildSimple();
var script = ScriptHelper.getExecScriptFile(sc, "sh"); var script = ScriptHelper.getExecScriptFile(sc, "sh");
Files.writeString(Path.of(script.toString()), rawCommand); Files.writeString(Path.of(script.toString()), rawCommand);
var fixedFile = script.toString().replaceAll("\\\\", "/").replaceAll("\\s", "\\$0"); var fixedFile = script.toString().replaceAll("\\\\", "/").replaceAll("\\s", "\\$0");
sc.command(CommandBuilder.of().addFile(file.toString()).add("-newtab").add(fixedFile)).execute(); sc.command(CommandBuilder.of()
.addFile(file.toString())
.add("-newtab")
.add(fixedFile))
.execute();
} }
} }
} }

View file

@ -11,7 +11,9 @@ import java.util.Optional;
public class SecureCrtTerminalType extends ExternalTerminalType.WindowsType { public class SecureCrtTerminalType extends ExternalTerminalType.WindowsType {
public SecureCrtTerminalType() {super("app.secureCrt", "SecureCRT");} public SecureCrtTerminalType() {
super("app.secureCrt", "SecureCRT");
}
@Override @Override
public TerminalOpenFormat getOpenFormat() { public TerminalOpenFormat getOpenFormat() {
@ -21,7 +23,8 @@ public class SecureCrtTerminalType extends ExternalTerminalType.WindowsType {
@Override @Override
protected Optional<Path> determineInstallation() { protected Optional<Path> determineInstallation() {
try (var sc = LocalShell.getShell().start()) { try (var sc = LocalShell.getShell().start()) {
var env = sc.executeSimpleStringCommand(sc.getShellDialect().getPrintEnvironmentVariableCommand("ProgramFiles")); var env = sc.executeSimpleStringCommand(
sc.getShellDialect().getPrintEnvironmentVariableCommand("ProgramFiles"));
var file = Path.of(env, "VanDyke Software\\SecureCRT\\SecureCRT.exe"); var file = Path.of(env, "VanDyke Software\\SecureCRT\\SecureCRT.exe");
if (!Files.exists(file)) { if (!Files.exists(file)) {
return Optional.empty(); return Optional.empty();
@ -54,8 +57,15 @@ public class SecureCrtTerminalType extends ExternalTerminalType.WindowsType {
try (var sc = LocalShell.getShell()) { try (var sc = LocalShell.getShell()) {
SshLocalBridge.init(); SshLocalBridge.init();
var b = SshLocalBridge.get(); var b = SshLocalBridge.get();
var command = CommandBuilder.of().addFile(file.toString()).add("/T").add("/SSH2", "/ACCEPTHOSTKEYS", "/I").addFile( var command = CommandBuilder.of()
b.getIdentityKey().toString()).add("/P", "" + b.getPort()).add("/L").addQuoted(b.getUser()).add("localhost"); .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); sc.executeSimpleCommand(command);
} }
} }

View file

@ -16,6 +16,7 @@ import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellDialect; import io.xpipe.core.process.ShellDialect;
import io.xpipe.core.process.ShellDialects; import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.store.FilePath; import io.xpipe.core.store.FilePath;
import lombok.Value; import lombok.Value;
import lombok.With; import lombok.With;
@ -41,8 +42,8 @@ public class TerminalLaunchConfiguration {
DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss").withZone(ZoneId.systemDefault()); DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss").withZone(ZoneId.systemDefault());
public static TerminalLaunchConfiguration create( public static TerminalLaunchConfiguration create(
UUID request, DataStoreEntry entry, String cleanTitle, String adjustedTitle, boolean preferTabs UUID request, DataStoreEntry entry, String cleanTitle, String adjustedTitle, boolean preferTabs)
) throws Exception { throws Exception {
var color = entry != null ? DataStorage.get().getEffectiveColor(entry) : null; var color = entry != null ? DataStorage.get().getEffectiveColor(entry) : null;
var d = ProcessControlProvider.get().getEffectiveLocalDialect(); var d = ProcessControlProvider.get().getEffectiveLocalDialect();
var launcherScript = d.terminalLauncherScript(request, adjustedTitle); var launcherScript = d.terminalLauncherScript(request, adjustedTitle);
@ -84,7 +85,12 @@ public class TerminalLaunchConfiguration {
logFile.getFileName().toString()); logFile.getFileName().toString());
var ps = ScriptHelper.createExecScript(ShellDialects.POWERSHELL, sc, content); var ps = ScriptHelper.createExecScript(ShellDialects.POWERSHELL, sc, content);
var config = new TerminalLaunchConfiguration( var config = new TerminalLaunchConfiguration(
entry != null ? color : null, adjustedTitle, cleanTitle, preferTabs, ps, ShellDialects.POWERSHELL); entry != null ? color : null,
adjustedTitle,
cleanTitle,
preferTabs,
ps,
ShellDialects.POWERSHELL);
return config; return config;
} else { } else {
var found = sc.command(sc.getShellDialect().getWhichCommand("script")) var found = sc.command(sc.getShellDialect().getWhichCommand("script"))

View file

@ -49,7 +49,8 @@ public class TerminalLauncher {
open(entry, title, directory, cc, UUID.randomUUID(), true); open(entry, title, directory, cc, UUID.randomUUID(), true);
} }
public static void open(DataStoreEntry entry, String title, String directory, ProcessControl cc, UUID request, boolean preferTabs) public static void open(
DataStoreEntry entry, String title, String directory, ProcessControl cc, UUID request, boolean preferTabs)
throws Exception { throws Exception {
var type = AppPrefs.get().terminalType().getValue(); var type = AppPrefs.get().terminalType().getValue();
if (type == null) { if (type == null) {

View file

@ -1,7 +1,6 @@
package io.xpipe.app.terminal; package io.xpipe.app.terminal;
public enum TerminalOpenFormat { public enum TerminalOpenFormat {
NEW_WINDOW, NEW_WINDOW,
TABBED, TABBED,
NEW_WINDOW_OR_TABBED; NEW_WINDOW_OR_TABBED;

View file

@ -49,13 +49,17 @@ public class TerminalView {
public static interface Listener { public static interface Listener {
default void onSessionOpened(ShellSession session) {}; default void onSessionOpened(ShellSession session) {}
;
default void onSessionClosed(ShellSession session) {}; default void onSessionClosed(ShellSession session) {}
;
default void onTerminalOpened(TerminalSession instance) {}; default void onTerminalOpened(TerminalSession instance) {}
;
default void onTerminalClosed(TerminalSession instance) {}; default void onTerminalClosed(TerminalSession instance) {}
;
} }
private final List<ShellSession> sessions = new ArrayList<>(); private final List<ShellSession> sessions = new ArrayList<>();
@ -130,7 +134,9 @@ public class TerminalView {
yield Optional.empty(); yield Optional.empty();
} }
var existing = terminalInstances.stream().map(terminalSession -> ((WindowsTerminalSession) terminalSession).getControl()).toList(); var existing = terminalInstances.stream()
.map(terminalSession -> ((WindowsTerminalSession) terminalSession).getControl())
.toList();
controls.removeAll(existing); controls.removeAll(existing);
if (controls.isEmpty()) { if (controls.isEmpty()) {
yield Optional.empty(); yield Optional.empty();

View file

@ -10,6 +10,7 @@ import io.xpipe.app.util.LocalShell;
import io.xpipe.app.util.SshLocalBridge; import io.xpipe.app.util.SshLocalBridge;
import io.xpipe.app.util.WindowsRegistry; import io.xpipe.app.util.WindowsRegistry;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType; import javafx.scene.control.ButtonType;
@ -41,7 +42,8 @@ public class TermiusTerminalType implements ExternalTerminalType {
yield Files.exists(Path.of("/Applications/Termius.app")); yield Files.exists(Path.of("/Applications/Termius.app"));
} }
case OsType.Windows windows -> { case OsType.Windows windows -> {
var r = WindowsRegistry.local().readValue(WindowsRegistry.HKEY_CURRENT_USER, "SOFTWARE\\Classes\\termius"); var r = WindowsRegistry.local()
.readValue(WindowsRegistry.HKEY_CURRENT_USER, "SOFTWARE\\Classes\\termius");
yield r.isPresent(); yield r.isPresent();
} }
}; };
@ -78,7 +80,8 @@ public class TermiusTerminalType implements ExternalTerminalType {
var port = b.getPort(); var port = b.getPort();
var user = b.getUser(); var user = b.getUser();
var name = b.getIdentityKey().getFileName().toString(); var name = b.getIdentityKey().getFileName().toString();
Hyperlinks.open("termius://app/host-sharing#label=" + name + "&ip=" + host + "&port=" + port + "&username=" + user + "&os=undefined"); Hyperlinks.open("termius://app/host-sharing#label=" + name + "&ip=" + host + "&port=" + port + "&username="
+ user + "&os=undefined");
} }
private boolean showInfo() throws IOException { private boolean showInfo() throws IOException {
@ -93,8 +96,13 @@ public class TermiusTerminalType implements ExternalTerminalType {
alert.setTitle(AppI18n.get("termiusSetup")); alert.setTitle(AppI18n.get("termiusSetup"));
alert.setAlertType(Alert.AlertType.NONE); alert.setAlertType(Alert.AlertType.NONE);
var activated = AppI18n.get().getMarkdownDocumentation("app:termiusSetup").formatted(b.getIdentityKey(), keyContent); var activated = AppI18n.get()
var markdown = new MarkdownComp(activated, s -> s).prefWidth(450).prefHeight(450).createRegion(); .getMarkdownDocumentation("app:termiusSetup")
.formatted(b.getIdentityKey(), keyContent);
var markdown = new MarkdownComp(activated, s -> s)
.prefWidth(450)
.prefHeight(450)
.createRegion();
alert.getDialogPane().setContent(markdown); alert.getDialogPane().setContent(markdown);
alert.getButtonTypes().add(new ButtonType(AppI18n.get("ok"), ButtonBar.ButtonData.OK_DONE)); alert.getButtonTypes().add(new ButtonType(AppI18n.get("ok"), ButtonBar.ButtonData.OK_DONE));

View file

@ -9,7 +9,9 @@ import io.xpipe.core.util.FailableFunction;
public class WarpTerminalType extends ExternalTerminalType.MacOsType { public class WarpTerminalType extends ExternalTerminalType.MacOsType {
public WarpTerminalType() {super("app.warp", "Warp");} public WarpTerminalType() {
super("app.warp", "Warp");
}
@Override @Override
public TerminalOpenFormat getOpenFormat() { public TerminalOpenFormat getOpenFormat() {
@ -43,18 +45,21 @@ public class WarpTerminalType extends ExternalTerminalType.MacOsType {
@Override @Override
public void launch(TerminalLaunchConfiguration configuration) throws Exception { public void launch(TerminalLaunchConfiguration configuration) throws Exception {
LocalShell.getShell().executeSimpleCommand(CommandBuilder.of() LocalShell.getShell()
.add("open", "-a") .executeSimpleCommand(CommandBuilder.of()
.addQuoted("Warp.app") .add("open", "-a")
.addFile(configuration.getScriptFile())); .addQuoted("Warp.app")
.addFile(configuration.getScriptFile()));
} }
@Override @Override
public FailableFunction<TerminalLaunchConfiguration, String, Exception> remoteLaunchCommand( public FailableFunction<TerminalLaunchConfiguration, String, Exception> remoteLaunchCommand(
ShellDialect systemDialect ShellDialect systemDialect) {
) {
return launchConfiguration -> { return launchConfiguration -> {
var toExecute = CommandBuilder.of().add("open", "-a").addQuoted("Warp.app").addFile(launchConfiguration.getScriptFile()); var toExecute = CommandBuilder.of()
.add("open", "-a")
.addQuoted("Warp.app")
.addFile(launchConfiguration.getScriptFile());
return toExecute.buildSimple(); return toExecute.buildSimple();
}; };
} }

View file

@ -19,7 +19,9 @@ public interface WindowsTerminalType extends ExternalTerminalType, TrackableTerm
ExternalTerminalType WINDOWS_TERMINAL_CANARY = new Canary(); ExternalTerminalType WINDOWS_TERMINAL_CANARY = new Canary();
private static CommandBuilder toCommand(TerminalLaunchConfiguration configuration) throws Exception { private static CommandBuilder toCommand(TerminalLaunchConfiguration configuration) throws Exception {
var cmd = CommandBuilder.of().addIf(configuration.isPreferTabs(), "-w", "1").add("nt"); var cmd = CommandBuilder.of()
.addIf(configuration.isPreferTabs(), "-w", "1")
.add("nt");
if (configuration.getColor() != null) { if (configuration.getColor() != null) {
cmd.add("--tabColor").addQuoted(configuration.getColor().toHexString()); cmd.add("--tabColor").addQuoted(configuration.getColor().toHexString());
@ -105,7 +107,8 @@ public interface WindowsTerminalType extends ExternalTerminalType, TrackableTerm
@Override @Override
public void launch(TerminalLaunchConfiguration configuration) throws Exception { public void launch(TerminalLaunchConfiguration configuration) throws Exception {
if (!isAvailable()) { if (!isAvailable()) {
throw ErrorEvent.expected(new IllegalArgumentException("Windows Terminal Preview is not installed at " + getPath())); throw ErrorEvent.expected(
new IllegalArgumentException("Windows Terminal Preview is not installed at " + getPath()));
} }
LocalShell.getShell() LocalShell.getShell()
@ -140,7 +143,8 @@ public interface WindowsTerminalType extends ExternalTerminalType, TrackableTerm
@Override @Override
public void launch(TerminalLaunchConfiguration configuration) throws Exception { public void launch(TerminalLaunchConfiguration configuration) throws Exception {
if (!isAvailable()) { if (!isAvailable()) {
throw ErrorEvent.expected(new IllegalArgumentException("Windows Terminal Canary is not installed at " + getPath())); throw ErrorEvent.expected(
new IllegalArgumentException("Windows Terminal Canary is not installed at " + getPath()));
} }
LocalShell.getShell() LocalShell.getShell()

View file

@ -9,6 +9,7 @@ import io.xpipe.app.util.LocalShell;
import io.xpipe.app.util.SshLocalBridge; import io.xpipe.app.util.SshLocalBridge;
import io.xpipe.app.util.WindowsRegistry; import io.xpipe.app.util.WindowsRegistry;
import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.CommandBuilder;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType; import javafx.scene.control.ButtonType;
@ -18,7 +19,9 @@ import java.util.Optional;
public class XShellTerminalType extends ExternalTerminalType.WindowsType { public class XShellTerminalType extends ExternalTerminalType.WindowsType {
public XShellTerminalType() {super("app.xShell", "Xshell");} public XShellTerminalType() {
super("app.xShell", "Xshell");
}
@Override @Override
public TerminalOpenFormat getOpenFormat() { public TerminalOpenFormat getOpenFormat() {
@ -28,8 +31,10 @@ public class XShellTerminalType extends ExternalTerminalType.WindowsType {
@Override @Override
protected Optional<Path> determineInstallation() { protected Optional<Path> determineInstallation() {
try { try {
var r = WindowsRegistry.local().readValue(WindowsRegistry.HKEY_LOCAL_MACHINE, var r = WindowsRegistry.local()
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Xshell.exe"); .readValue(
WindowsRegistry.HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Xshell.exe");
return r.map(Path::of); return r.map(Path::of);
} catch (Exception e) { } catch (Exception e) {
ErrorEvent.fromThrowable(e).omit().handle(); ErrorEvent.fromThrowable(e).omit().handle();
@ -83,8 +88,12 @@ public class XShellTerminalType extends ExternalTerminalType.WindowsType {
alert.setTitle(AppI18n.get("xshellSetup")); alert.setTitle(AppI18n.get("xshellSetup"));
alert.setAlertType(Alert.AlertType.NONE); alert.setAlertType(Alert.AlertType.NONE);
var activated = AppI18n.get().getMarkdownDocumentation("app:xshellSetup").formatted(b.getIdentityKey(), keyName); var activated =
var markdown = new MarkdownComp(activated, s -> s).prefWidth(450).prefHeight(400).createRegion(); AppI18n.get().getMarkdownDocumentation("app:xshellSetup").formatted(b.getIdentityKey(), keyName);
var markdown = new MarkdownComp(activated, s -> s)
.prefWidth(450)
.prefHeight(400)
.createRegion();
alert.getDialogPane().setContent(markdown); alert.getDialogPane().setContent(markdown);
alert.getButtonTypes().add(new ButtonType(AppI18n.get("ok"), ButtonBar.ButtonData.OK_DONE)); alert.getButtonTypes().add(new ButtonType(AppI18n.get("ok"), ButtonBar.ButtonData.OK_DONE));

View file

@ -3,7 +3,6 @@ package io.xpipe.app.update;
import io.xpipe.app.comp.base.MarkdownComp; import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.window.AppWindowHelper; import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.Hyperlinks; import io.xpipe.app.util.Hyperlinks;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;

View file

@ -214,8 +214,7 @@ public abstract class UpdateHandler {
// We only do that here to minimize the sent requests by only executing when it's really necessary // We only do that here to minimize the sent requests by only executing when it's really necessary
var available = XPipeDistributionType.get() var available = XPipeDistributionType.get()
.getUpdateHandler() .getUpdateHandler()
.refreshUpdateCheckSilent( .refreshUpdateCheckSilent(false, preparedUpdate.getValue().isSecurityOnly());
false, preparedUpdate.getValue().isSecurityOnly());
if (preparedUpdate.getValue() == null) { if (preparedUpdate.getValue() == null) {
return; return;
} }

View file

@ -4,7 +4,6 @@ import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.CommandBuilder;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellDialect;
import io.xpipe.core.process.ShellDialects; import io.xpipe.core.process.ShellDialects;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -59,7 +58,8 @@ public class FileOpener {
try (var pc = LocalShell.getShell().start()) { try (var pc = LocalShell.getShell().start()) {
if (pc.getOsType().equals(OsType.WINDOWS)) { if (pc.getOsType().equals(OsType.WINDOWS)) {
if (pc.getShellDialect() == ShellDialects.POWERSHELL) { if (pc.getShellDialect() == ShellDialects.POWERSHELL) {
pc.command(CommandBuilder.of().add("Invoke-Item").addFile(localFile)).execute(); pc.command(CommandBuilder.of().add("Invoke-Item").addFile(localFile))
.execute();
} else { } else {
pc.executeSimpleCommand("start \"\" \"" + localFile + "\""); pc.executeSimpleCommand("start \"\" \"" + localFile + "\"");
} }

View file

@ -2,7 +2,6 @@ package io.xpipe.app.util;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import java.util.Optional; import java.util.Optional;

View file

@ -10,7 +10,6 @@ import io.xpipe.core.util.InPlaceSecretValue;
import javafx.beans.property.*; import javafx.beans.property.*;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.geometry.Orientation; import javafx.geometry.Orientation;
import javafx.scene.control.Label;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
import atlantafx.base.controls.Spacer; import atlantafx.base.controls.Spacer;
@ -138,12 +137,7 @@ public class OptionsBuilder {
public OptionsBuilder addTitle(ObservableValue<String> title) { public OptionsBuilder addTitle(ObservableValue<String> title) {
finishCurrent(); finishCurrent();
entries.add(new OptionsComp.Entry( entries.add(new OptionsComp.Entry(null, null, null, null, new LabelComp(title).styleClass("title-header")));
null,
null,
null,
null,
new LabelComp(title).styleClass("title-header")));
return this; return this;
} }

View file

@ -6,14 +6,12 @@ import io.xpipe.app.browser.file.BrowserEntry;
import io.xpipe.app.browser.file.BrowserFileSystemTabModel; import io.xpipe.app.browser.file.BrowserFileSystemTabModel;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.terminal.TerminalLauncher;
import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.CommandBuilder;
import io.xpipe.core.process.ShellControl; import io.xpipe.core.process.ShellControl;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import java.util.List; import java.util.List;
import java.util.UUID;
public abstract class MultiExecuteAction implements BrowserBranchAction { public abstract class MultiExecuteAction implements BrowserBranchAction {
@ -36,10 +34,14 @@ public abstract class MultiExecuteAction implements BrowserBranchAction {
} }
var cmd = pc.command(c); var cmd = pc.command(c);
model.openTerminalAsync(entry.getRawFileEntry().getName(), model.getCurrentDirectory() != null model.openTerminalAsync(
? model.getCurrentDirectory() entry.getRawFileEntry().getName(),
.getPath() model.getCurrentDirectory() != null
: null, cmd, entries.size() == 1); ? model.getCurrentDirectory()
.getPath()
: null,
cmd,
entries.size() == 1);
} }
}, },
false); false);

View file

@ -7,7 +7,6 @@ import io.xpipe.app.browser.file.BrowserFileSystemTabModel;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.terminal.TerminalLauncher;
import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.CommandBuilder;
import io.xpipe.core.process.ProcessOutputException; import io.xpipe.core.process.ProcessOutputException;
import io.xpipe.core.process.ShellControl; import io.xpipe.core.process.ShellControl;
@ -15,7 +14,6 @@ import io.xpipe.core.process.ShellControl;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
public abstract class MultiExecuteSelectionAction implements BrowserBranchAction { public abstract class MultiExecuteSelectionAction implements BrowserBranchAction {
@ -40,10 +38,14 @@ public abstract class MultiExecuteSelectionAction implements BrowserBranchAction
} }
var cmd = pc.command(c); var cmd = pc.command(c);
model.openTerminalAsync(getTerminalTitle(), model.getCurrentDirectory() != null model.openTerminalAsync(
? model.getCurrentDirectory() getTerminalTitle(),
.getPath() model.getCurrentDirectory() != null
: null, cmd, true); ? model.getCurrentDirectory()
.getPath()
: null,
cmd,
true);
}, },
false); false);
} }

View file

@ -1,10 +1,8 @@
package io.xpipe.ext.base.browser; package io.xpipe.ext.base.browser;
import io.xpipe.app.browser.BrowserFullSessionModel;
import io.xpipe.app.browser.action.BrowserLeafAction; import io.xpipe.app.browser.action.BrowserLeafAction;
import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.file.BrowserEntry;
import io.xpipe.app.browser.file.BrowserFileSystemTabModel; import io.xpipe.app.browser.file.BrowserFileSystemTabModel;
import io.xpipe.app.browser.file.BrowserTerminalDockTabModel;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileKind;
@ -17,7 +15,6 @@ import javafx.scene.input.KeyCombination;
import org.kordamp.ikonli.javafx.FontIcon; import org.kordamp.ikonli.javafx.FontIcon;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -25,9 +22,13 @@ public class OpenTerminalAction implements BrowserLeafAction {
@Override @Override
public void execute(BrowserFileSystemTabModel model, List<BrowserEntry> entries) { public void execute(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
var dirs = entries.size() > 0 ? entries.stream().map(browserEntry -> browserEntry.getRawFileEntry().getPath()).toList() : model.getCurrentDirectory() != null var dirs = entries.size() > 0
? List.of(model.getCurrentDirectory().getPath()) ? entries.stream()
: Collections.singletonList((String) null); .map(browserEntry -> browserEntry.getRawFileEntry().getPath())
.toList()
: model.getCurrentDirectory() != null
? List.of(model.getCurrentDirectory().getPath())
: Collections.singletonList((String) null);
for (String dir : dirs) { for (String dir : dirs) {
var name = (dir != null ? dir + " - " : "") + model.getName(); var name = (dir != null ? dir + " - " : "") + model.getName();
model.openTerminalAsync(name, dir, model.getFileSystem().getShell().orElseThrow(), dirs.size() == 1); model.openTerminalAsync(name, dir, model.getFileSystem().getShell().orElseThrow(), dirs.size() == 1);