mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-22 07:30:24 +00:00
Color improvements and terminal fixes
This commit is contained in:
parent
993e1d5446
commit
f277cc0a37
14 changed files with 243 additions and 182 deletions
|
@ -7,7 +7,6 @@ import io.xpipe.app.storage.DataStoreEntryRef;
|
|||
import io.xpipe.app.util.BooleanScope;
|
||||
import io.xpipe.app.util.TerminalHelper;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import io.xpipe.core.store.FileNames;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.process.ShellDialects;
|
||||
import io.xpipe.core.store.*;
|
||||
|
@ -46,7 +45,7 @@ public final class OpenFileSystemModel {
|
|||
public OpenFileSystemModel(BrowserModel browserModel, DataStoreEntryRef<? extends FileSystemStore> entry) {
|
||||
this.browserModel = browserModel;
|
||||
this.entry = entry;
|
||||
this.name = entry.get().getName();
|
||||
this.name = DataStorage.get().getStoreBrowserDisplayName(entry.get());
|
||||
this.tooltip = DataStorage.get().getId(entry.getEntry()).toString();
|
||||
this.inOverview.bind(Bindings.createBooleanBinding(
|
||||
() -> {
|
||||
|
@ -147,32 +146,29 @@ public final class OpenFileSystemModel {
|
|||
}
|
||||
|
||||
// Handle commands typed into navigation bar
|
||||
if (allowCommands && evaluatedPath != null && !FileNames.isAbsolute(evaluatedPath)
|
||||
if (allowCommands
|
||||
&& evaluatedPath != null
|
||||
&& !FileNames.isAbsolute(evaluatedPath)
|
||||
&& fileSystem.getShell().isPresent()) {
|
||||
var directory = currentPath.get();
|
||||
var name = adjustedPath + " - " + entry.get().getName();
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
if (ShellDialects.ALL.stream()
|
||||
.anyMatch(dialect -> adjustedPath.startsWith(dialect.getOpenCommand()))) {
|
||||
var cmd = fileSystem
|
||||
if (ShellDialects.ALL.stream().anyMatch(dialect -> adjustedPath.startsWith(dialect.getOpenCommand()))) {
|
||||
TerminalHelper.open(entry.getEntry(), name, fileSystem
|
||||
.getShell()
|
||||
.get()
|
||||
.subShell(adjustedPath)
|
||||
.initWith(fileSystem
|
||||
.getShell()
|
||||
.get()
|
||||
.getShellDialect()
|
||||
.getCdCommand(currentPath.get()))
|
||||
.prepareTerminalOpen(name);
|
||||
TerminalHelper.open(adjustedPath, cmd);
|
||||
.getShell()
|
||||
.get()
|
||||
.getShellDialect()
|
||||
.getCdCommand(currentPath.get())));
|
||||
} else {
|
||||
var cmd = fileSystem
|
||||
TerminalHelper.open(entry.getEntry(), name, fileSystem
|
||||
.getShell()
|
||||
.get()
|
||||
.command(adjustedPath)
|
||||
.withWorkingDirectory(directory)
|
||||
.prepareTerminalOpen(name);
|
||||
TerminalHelper.open(adjustedPath, cmd);
|
||||
.withWorkingDirectory(directory));
|
||||
}
|
||||
});
|
||||
return Optional.ofNullable(currentPath.get());
|
||||
|
@ -394,10 +390,9 @@ public final class OpenFileSystemModel {
|
|||
BooleanScope.execute(busy, () -> {
|
||||
if (entry.getStore() instanceof ShellStore s) {
|
||||
var connection = ((ConnectionFileSystem) fileSystem).getShellControl();
|
||||
var command = s.control()
|
||||
.initWith(connection.getShellDialect().getCdCommand(directory))
|
||||
.prepareTerminalOpen(directory + " - " + entry.get().getName());
|
||||
TerminalHelper.open(directory, command);
|
||||
var name = directory + " - " + entry.get().getName();
|
||||
TerminalHelper.open(entry.getEntry(), name, s.control()
|
||||
.initWith(connection.getShellDialect().getCdCommand(directory)));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,6 @@ import io.xpipe.app.browser.OpenFileSystemModel;
|
|||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.util.ScriptHelper;
|
||||
import io.xpipe.app.util.TerminalHelper;
|
||||
import io.xpipe.core.store.FileNames;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
|
@ -29,15 +28,10 @@ public abstract class MultiExecuteAction implements BranchAction {
|
|||
model.withShell(
|
||||
pc -> {
|
||||
for (BrowserEntry entry : entries) {
|
||||
var cmd = pc.command(createCommand(pc, model, entry))
|
||||
TerminalHelper.open(model.getEntry().getEntry(), FilenameUtils.getBaseName(
|
||||
entry.getRawFileEntry().getPath()), pc.command(createCommand(pc, model, entry))
|
||||
.withWorkingDirectory(model.getCurrentDirectory()
|
||||
.getPath())
|
||||
.prepareTerminalOpen(FileNames.getFileName(
|
||||
entry.getRawFileEntry().getPath()));
|
||||
TerminalHelper.open(
|
||||
FilenameUtils.getBaseName(
|
||||
entry.getRawFileEntry().getPath()),
|
||||
cmd);
|
||||
.getPath()));
|
||||
}
|
||||
},
|
||||
false);
|
||||
|
|
|
@ -15,7 +15,7 @@ public class LaunchExchangeImpl extends LaunchExchange
|
|||
public Response handleRequest(BeaconHandler handler, Request msg) throws Exception {
|
||||
var store = getStoreEntryById(msg.getId(), false);
|
||||
if (store.getStore() instanceof LaunchableStore s) {
|
||||
var command = s.prepareLaunchCommand(store.getName());
|
||||
var command = s.prepareLaunchCommand().prepareTerminalOpen(store.getName());
|
||||
return Response.builder().command(split(command)).build();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,16 +2,18 @@ package io.xpipe.app.prefs;
|
|||
|
||||
import io.xpipe.app.ext.PrefsChoiceValue;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.storage.DataStoreColor;
|
||||
import io.xpipe.app.util.ApplicationHelper;
|
||||
import io.xpipe.app.util.MacOsPermissions;
|
||||
import io.xpipe.app.util.ScriptHelper;
|
||||
import io.xpipe.app.util.WindowsRegistry;
|
||||
import io.xpipe.core.store.FileNames;
|
||||
import io.xpipe.core.store.LocalStore;
|
||||
import io.xpipe.core.process.CommandBuilder;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.store.FileNames;
|
||||
import io.xpipe.core.store.LocalStore;
|
||||
import lombok.Getter;
|
||||
import lombok.Value;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
@ -22,11 +24,21 @@ import java.util.stream.Stream;
|
|||
|
||||
public interface ExternalTerminalType extends PrefsChoiceValue {
|
||||
|
||||
ExternalTerminalType CMD = new SimplePathType("app.cmd", "cmd.exe") {
|
||||
ExternalTerminalType CMD = new PathType("app.cmd", "cmd.exe") {
|
||||
|
||||
@Override
|
||||
protected CommandBuilder toCommand(String name, String file) {
|
||||
return CommandBuilder.of().add("/C").addFile(file);
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
LocalStore.getShell()
|
||||
.executeSimpleCommand(CommandBuilder.of()
|
||||
.add("start")
|
||||
.addQuoted(configuration.getTitle())
|
||||
.add("cmd", "/c")
|
||||
.addFile(configuration.getScriptFile()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,7 +51,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
|
||||
@Override
|
||||
protected CommandBuilder toCommand(String name, String file) {
|
||||
return CommandBuilder.of().add("-ExecutionPolicy", "RemoteSigned", "-NoProfile", "-Command", "cmd", "/C", "'" + file + "'");
|
||||
return CommandBuilder.of()
|
||||
.add("-ExecutionPolicy", "RemoteSigned", "-NoProfile", "-Command", "cmd", "/C", "'" + file + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,10 +66,13 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
@Override
|
||||
protected CommandBuilder toCommand(String name, String file) {
|
||||
// Fix for https://github.com/PowerShell/PowerShell/issues/18530#issuecomment-1325691850
|
||||
return CommandBuilder.of().add("-ExecutionPolicy", "RemoteSigned", "-NoProfile", "-Command", "cmd", "/C").add(sc -> {
|
||||
var script = ScriptHelper.createLocalExecScript("set \"PSModulePath=\"\r\n\"" + file + "\"\npause");
|
||||
return "'" + script + "'";
|
||||
});
|
||||
return CommandBuilder.of()
|
||||
.add("-ExecutionPolicy", "RemoteSigned", "-NoProfile", "-Command", "cmd", "/C")
|
||||
.add(sc -> {
|
||||
var script =
|
||||
ScriptHelper.createLocalExecScript("set \"PSModulePath=\"\r\n\"" + file + "\"\npause");
|
||||
return "'" + script + "'";
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,15 +81,19 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
};
|
||||
|
||||
ExternalTerminalType WINDOWS_TERMINAL = new SimplePathType("app.windowsTerminal", "wt.exe") {
|
||||
ExternalTerminalType WINDOWS_TERMINAL = new PathType("app.windowsTerminal", "wt.exe") {
|
||||
|
||||
@Override
|
||||
protected CommandBuilder toCommand(String name, String file) {
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
// A weird behavior in Windows Terminal causes the trailing
|
||||
// backslash of a filepath to escape the closing quote in the title argument
|
||||
// So just remove that slash
|
||||
var fixedName = FileNames.removeTrailingSlash(name);
|
||||
return CommandBuilder.of().add("-w", "1", "nt", "--title").addQuoted(fixedName).addFile(file);
|
||||
var fixedName = FileNames.removeTrailingSlash(configuration.getTitle());
|
||||
LocalStore.getShell()
|
||||
.executeSimpleCommand(CommandBuilder.of()
|
||||
.add("wt", "-w", "1", "nt", "--title")
|
||||
.addQuoted(fixedName)
|
||||
.addFile(configuration.getScriptFile()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,17 +102,28 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
};
|
||||
|
||||
ExternalTerminalType ALACRITTY_WINDOWS = new SimplePathType("app.alacrittyWindows", "alacritty") {
|
||||
ExternalTerminalType ALACRITTY_WINDOWS = new PathType("app.alacrittyWindows", "alacritty") {
|
||||
|
||||
@Override
|
||||
protected CommandBuilder toCommand(String name, String file) {
|
||||
return CommandBuilder.of()
|
||||
.add("-t")
|
||||
.addQuoted(name)
|
||||
.add("-e")
|
||||
.add("cmd")
|
||||
.add("/c")
|
||||
.addQuoted(file.replaceAll(" ", "^$0"));
|
||||
public boolean supportsColoredTitle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
var b = CommandBuilder.of().add("alacritty");
|
||||
if (configuration.getColor() != null) {
|
||||
b.add("-o")
|
||||
.addQuoted("colors.primary.background='%s'"
|
||||
.formatted(configuration.getColor().toHexString()));
|
||||
}
|
||||
LocalStore.getShell()
|
||||
.executeSimpleCommand(b.add("-t")
|
||||
.addQuoted(configuration.getTitle())
|
||||
.add("-e")
|
||||
.add("cmd")
|
||||
.add("/c")
|
||||
.addQuoted(configuration.getScriptFile().replaceAll(" ", "^$0")));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -100,15 +131,15 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
return OsType.getLocal().equals(OsType.WINDOWS);
|
||||
}
|
||||
};
|
||||
abstract class WindowsType extends ExternalApplicationType.WindowsType
|
||||
implements ExternalTerminalType {
|
||||
|
||||
abstract class WindowsType extends ExternalApplicationType.WindowsType implements ExternalTerminalType {
|
||||
|
||||
public WindowsType(String id, String executable) {
|
||||
super(id, executable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launch(String name, String file) throws Exception {
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
var location = determineFromPath();
|
||||
if (location.isEmpty()) {
|
||||
location = determineInstallation();
|
||||
|
@ -118,19 +149,20 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
|
||||
Optional<Path> finalLocation = location;
|
||||
ApplicationHelper.executeLocalApplication(
|
||||
sc -> createCommand(sc, name, finalLocation.get().toString(), file), false);
|
||||
execute(location.get(), configuration);
|
||||
}
|
||||
|
||||
protected abstract String createCommand(ShellControl shellControl, String name, String path, String file);
|
||||
protected abstract void execute(Path file, LaunchConfiguration configuration) throws Exception;
|
||||
}
|
||||
|
||||
ExternalTerminalType TABBY_WINDOWS = new WindowsType("app.tabbyWindows", "Tabby") {
|
||||
|
||||
@Override
|
||||
protected String createCommand(ShellControl shellControl, String name, String path, String file) {
|
||||
return shellControl.getShellDialect().fileArgument(path) + " run "
|
||||
+ shellControl.getShellDialect().fileArgument(file);
|
||||
protected void execute(Path file, LaunchConfiguration configuration) throws Exception {
|
||||
ApplicationHelper.executeLocalApplication(
|
||||
shellControl -> shellControl.getShellDialect().fileArgument(file.toString()) + " run "
|
||||
+ shellControl.getShellDialect().fileArgument(configuration.getScriptFile()),
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -145,34 +177,39 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
};
|
||||
|
||||
// ExternalTerminalType HYPER_WINDOWS = new WindowsFullPathType("app.hyperWindows") {
|
||||
//
|
||||
// @Override
|
||||
// protected String createCommand(ShellControl shellControl, String name, String path, String file) {
|
||||
// return shellControl.getShellDialect().fileArgument(path) + " "
|
||||
// + shellControl.getShellDialect().fileArgument(file);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected Optional<Path> determinePath() {
|
||||
// Optional<String> launcherDir;
|
||||
// launcherDir = WindowsRegistry.readString(
|
||||
// WindowsRegistry.HKEY_CURRENT_USER,
|
||||
// "SOFTWARE\\ac619139-e2f9-5cb9-915f-69b22e7bff50",
|
||||
// "InstallLocation")
|
||||
// .map(p -> p + "\\Hyper.exe");
|
||||
// return launcherDir.map(Path::of);
|
||||
// }
|
||||
// };
|
||||
// ExternalTerminalType HYPER_WINDOWS = new WindowsFullPathType("app.hyperWindows") {
|
||||
//
|
||||
// @Override
|
||||
// protected String createCommand(ShellControl shellControl, String name, String path, String file) {
|
||||
// return shellControl.getShellDialect().fileArgument(path) + " "
|
||||
// + shellControl.getShellDialect().fileArgument(file);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected Optional<Path> determinePath() {
|
||||
// Optional<String> launcherDir;
|
||||
// launcherDir = WindowsRegistry.readString(
|
||||
// WindowsRegistry.HKEY_CURRENT_USER,
|
||||
// "SOFTWARE\\ac619139-e2f9-5cb9-915f-69b22e7bff50",
|
||||
// "InstallLocation")
|
||||
// .map(p -> p + "\\Hyper.exe");
|
||||
// return launcherDir.map(Path::of);
|
||||
// }
|
||||
// };
|
||||
|
||||
ExternalTerminalType GNOME_TERMINAL = new SimplePathType("app.gnomeTerminal", "gnome-terminal") {
|
||||
ExternalTerminalType GNOME_TERMINAL = new PathType("app.gnomeTerminal", "gnome-terminal") {
|
||||
|
||||
@Override
|
||||
public void launch(String name, String file) throws Exception {
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
try (ShellControl pc = LocalStore.getShell()) {
|
||||
ApplicationHelper.isInPath(pc, executable, toTranslatedString(), null);
|
||||
ApplicationHelper.checkIsInPath(pc, executable, toTranslatedString(), null);
|
||||
|
||||
var toExecute = executable + " " + toCommand(name, file).build(pc);
|
||||
var toExecute = CommandBuilder.of()
|
||||
.add(executable, "-v", "--title")
|
||||
.addQuoted(configuration.getTitle())
|
||||
.add("--")
|
||||
.addFile(configuration.getScriptFile())
|
||||
.build(pc);
|
||||
// In order to fix this bug which also affects us:
|
||||
// https://askubuntu.com/questions/1148475/launching-gnome-terminal-from-vscode
|
||||
toExecute = "GNOME_TERMINAL_SCREEN=\"\" nohup " + toExecute + " </dev/null &>/dev/null & disown";
|
||||
|
@ -180,11 +217,6 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CommandBuilder toCommand(String name, String file) {
|
||||
return CommandBuilder.of().add("-v", "--title").addQuoted(name).add("--").addFile(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelectable() {
|
||||
return OsType.getLocal().equals(OsType.LINUX);
|
||||
|
@ -211,7 +243,11 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
|
||||
@Override
|
||||
protected CommandBuilder toCommand(String name, String file) {
|
||||
return CommandBuilder.of().add("--tab", "--title").addQuoted(name).add("--command").addFile(file);
|
||||
return CommandBuilder.of()
|
||||
.add("--tab", "--title")
|
||||
.addQuoted(name)
|
||||
.add("--command")
|
||||
.addFile(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -286,11 +322,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
|
||||
@Override
|
||||
protected CommandBuilder toCommand(String name, String file) {
|
||||
return CommandBuilder.of()
|
||||
.add("-T")
|
||||
.addQuoted(name)
|
||||
.add("-e")
|
||||
.addQuoted(file);
|
||||
return CommandBuilder.of().add("-T").addQuoted(name).add("-e").addQuoted(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -303,11 +335,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
|
||||
@Override
|
||||
protected CommandBuilder toCommand(String name, String file) {
|
||||
return CommandBuilder.of()
|
||||
.add("-r")
|
||||
.addQuoted(name)
|
||||
.add("-e")
|
||||
.addQuoted(file);
|
||||
return CommandBuilder.of().add("-r").addQuoted(name).add("-e").addQuoted(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -320,11 +348,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
|
||||
@Override
|
||||
protected CommandBuilder toCommand(String name, String file) {
|
||||
return CommandBuilder.of()
|
||||
.add("-t")
|
||||
.addQuoted(name)
|
||||
.add("-e")
|
||||
.addQuoted(file);
|
||||
return CommandBuilder.of().add("-t").addQuoted(name).add("-e").addQuoted(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -357,32 +381,30 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
ExternalTerminalType ALACRITTY_MACOS = new MacOsType("app.alacrittyMacOs", "Alacritty") {
|
||||
|
||||
@Override
|
||||
public void launch(String name, String file) throws Exception {
|
||||
try (ShellControl pc = new LocalStore().control().start()) {
|
||||
pc.command(String.format(
|
||||
"""
|
||||
%s/Contents/MacOS/alacritty -t "%s" -e %s
|
||||
""",
|
||||
getApplicationPath().orElseThrow(),
|
||||
name,
|
||||
pc.getShellDialect().fileArgument(file)))
|
||||
.execute();
|
||||
}
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
LocalStore.getShell()
|
||||
.executeSimpleCommand(CommandBuilder.of()
|
||||
.add("open", "-a")
|
||||
.addQuoted("Alacritty.app")
|
||||
.add("-n", "--args", "-t")
|
||||
.addQuoted(configuration.getTitle())
|
||||
.add("-e")
|
||||
.addFile(configuration.getScriptFile()));
|
||||
}
|
||||
};
|
||||
|
||||
ExternalTerminalType KITTY_MACOS = new MacOsType("app.kittyMacOs", "kitty") {
|
||||
|
||||
@Override
|
||||
public void launch(String name, String file) throws Exception {
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
try (ShellControl pc = new LocalStore().control().start()) {
|
||||
pc.command(String.format(
|
||||
"""
|
||||
%s/Contents/MacOS/kitty -T "%s" %s
|
||||
""",
|
||||
getApplicationPath().orElseThrow(),
|
||||
name,
|
||||
pc.getShellDialect().fileArgument(file)))
|
||||
configuration.getTitle(),
|
||||
pc.getShellDialect().fileArgument(configuration.getScriptFile())))
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
@ -426,7 +448,23 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
.orElse(null);
|
||||
}
|
||||
|
||||
void launch(String name, String file) throws Exception;
|
||||
@Value
|
||||
static class LaunchConfiguration {
|
||||
|
||||
DataStoreColor color;
|
||||
String title;
|
||||
String scriptFile;
|
||||
|
||||
public String getColorPrefix() {
|
||||
return color != null ? color.getEmoji() + " " : "";
|
||||
}
|
||||
}
|
||||
|
||||
default boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
default void launch(LaunchConfiguration configuration) throws Exception {}
|
||||
|
||||
class MacOsTerminalType extends ExternalApplicationType.MacApplication implements ExternalTerminalType {
|
||||
|
||||
|
@ -435,9 +473,9 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void launch(String name, String file) throws Exception {
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
try (ShellControl pc = LocalStore.getShell()) {
|
||||
var suffix = "\"" + file.replaceAll("\"", "\\\\\"") + "\"";
|
||||
var suffix = "\"" + configuration.getScriptFile().replaceAll("\"", "\\\\\"") + "\"";
|
||||
pc.osascriptCommand(String.format(
|
||||
"""
|
||||
activate application "Terminal"
|
||||
|
@ -456,7 +494,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void launch(String name, String file) throws Exception {
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
var custom = AppPrefs.get().customTerminalCommand().getValue();
|
||||
if (custom == null || custom.isBlank()) {
|
||||
throw ErrorEvent.unreportable(new IllegalStateException("No custom terminal command specified"));
|
||||
|
@ -464,9 +502,10 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
|
||||
var format = custom.toLowerCase(Locale.ROOT).contains("$cmd") ? custom : custom + " $CMD";
|
||||
try (var pc = LocalStore.getShell()) {
|
||||
var toExecute = ApplicationHelper.replaceFileArgument(format, "CMD", file);
|
||||
var toExecute = ApplicationHelper.replaceFileArgument(format, "CMD", configuration.getScriptFile());
|
||||
// We can't be sure whether the command is blocking or not, so always make it not blocking
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
toExecute = "start \"" + name + "\" " + toExecute;
|
||||
toExecute = "start \"" + configuration.getTitle() + "\" " + toExecute;
|
||||
} else {
|
||||
toExecute = "nohup " + toExecute + " </dev/null &>/dev/null & disown";
|
||||
}
|
||||
|
@ -492,7 +531,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void launch(String name, String file) throws Exception {
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
var app = this.getApplicationPath();
|
||||
if (app.isEmpty()) {
|
||||
throw new IllegalStateException("iTerm installation not found");
|
||||
|
@ -515,7 +554,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
create window with default profile command "%s"
|
||||
end tell
|
||||
""",
|
||||
a, a, a, a, file.replaceAll("\"", "\\\\\"")))
|
||||
a, a, a, a, configuration.getScriptFile().replaceAll("\"", "\\\\\"")))
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
@ -528,16 +567,13 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void launch(String name, String file) throws Exception {
|
||||
try (ShellControl pc = new LocalStore().control().start()) {
|
||||
pc.command(String.format(
|
||||
"""
|
||||
%s/Contents/MacOS/Tabby run %s
|
||||
""",
|
||||
getApplicationPath().orElseThrow(),
|
||||
pc.getShellDialect().fileArgument(file)))
|
||||
.execute();
|
||||
}
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
LocalStore.getShell()
|
||||
.executeSimpleCommand(CommandBuilder.of()
|
||||
.add("open", "-a")
|
||||
.addQuoted("Tabby.app")
|
||||
.add("-n", "--args", "run")
|
||||
.addFile(configuration.getScriptFile()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -548,7 +584,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void launch(String name, String file) throws Exception {
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
if (!MacOsPermissions.waitForAccessibilityPermissions()) {
|
||||
return;
|
||||
}
|
||||
|
@ -567,7 +603,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
end tell
|
||||
end tell
|
||||
""",
|
||||
file.replaceAll("\"", "\\\\\"")))
|
||||
configuration.getScriptFile().replaceAll("\"", "\\\\\"")))
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
@ -581,29 +617,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
|
||||
@Getter
|
||||
abstract class SimplePathType extends ExternalApplicationType.PathApplication implements ExternalTerminalType {
|
||||
abstract class PathType extends ExternalApplicationType.PathApplication implements ExternalTerminalType {
|
||||
|
||||
public SimplePathType(String id, String executable) {
|
||||
public PathType(String id, String executable) {
|
||||
super(id, executable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launch(String name, String file) throws Exception {
|
||||
try (ShellControl pc = LocalStore.getShell()) {
|
||||
ApplicationHelper.isInPath(pc, executable, toTranslatedString(), null);
|
||||
|
||||
var toExecute = executable + " " + toCommand(name, file).build(pc);
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
toExecute = "start \"" + name + "\" " + toExecute;
|
||||
} else {
|
||||
toExecute = "nohup " + toExecute + " </dev/null &>/dev/null & disown";
|
||||
}
|
||||
pc.executeSimpleCommand(toExecute);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract CommandBuilder toCommand(String name, String file);
|
||||
|
||||
public boolean isAvailable() {
|
||||
try (ShellControl pc = LocalStore.getShell()) {
|
||||
return pc.executeSimpleBooleanCommand(pc.getShellDialect().getWhichCommand(executable));
|
||||
|
@ -618,4 +637,31 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
abstract class SimplePathType extends PathType {
|
||||
|
||||
public SimplePathType(String id, String executable) {
|
||||
super(id, executable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
try (ShellControl pc = LocalStore.getShell()) {
|
||||
ApplicationHelper.checkIsInPath(pc, executable, toTranslatedString(), null);
|
||||
|
||||
var toExecute = executable + " "
|
||||
+ toCommand(configuration.getTitle(), configuration.getScriptFile())
|
||||
.build(pc);
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
toExecute = "start \"" + configuration.getTitle() + "\" " + toExecute;
|
||||
} else {
|
||||
toExecute = "nohup " + toExecute + " </dev/null &>/dev/null & disown";
|
||||
}
|
||||
pc.executeSimpleCommand(toExecute);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract CommandBuilder toCommand(String name, String file);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public class TroubleshootComp extends Comp<CompStructure<?>> {
|
|||
sc.executeSimpleCommand(
|
||||
ScriptHelper.createDetachCommand(sc, "\"" + script + "\""));
|
||||
} else {
|
||||
TerminalHelper.open("XPipe Debug", "\"" + script + "\"");
|
||||
TerminalHelper.open("XPipe Debug", LocalStore.getShell().command("\"" + script + "\""));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,27 +1,41 @@
|
|||
package io.xpipe.app.storage;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import javafx.scene.paint.Color;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum DataStoreColor {
|
||||
@JsonProperty("red")
|
||||
RED("red", "\uD83D\uDFE5"),
|
||||
RED("red", "\uD83D\uDFE5", Color.BLUE),
|
||||
|
||||
@JsonProperty("green")
|
||||
GREEN("green", "\uD83D\uDFE9"),
|
||||
GREEN("green", "\uD83D\uDFE9", Color.BLUE),
|
||||
|
||||
@JsonProperty("yellow")
|
||||
YELLOW("yellow", "\uD83D\uDFE8"),
|
||||
YELLOW("yellow", "\uD83D\uDFE8", Color.BLUE),
|
||||
|
||||
@JsonProperty("blue")
|
||||
BLUE("blue", "\uD83D\uDFE6");
|
||||
BLUE("blue", "\uD83D\uDD35", Color.BLUE);
|
||||
|
||||
private final String id;
|
||||
private final String emoji;
|
||||
private final Color terminalColor;
|
||||
|
||||
DataStoreColor(String id, String emoji) {
|
||||
DataStoreColor(String id, String emoji, Color terminalColor) {
|
||||
this.id = id;
|
||||
this.emoji = emoji;
|
||||
this.terminalColor = terminalColor;
|
||||
}
|
||||
|
||||
private String format(double val) {
|
||||
String in = Integer.toHexString((int) Math.round(val * 255));
|
||||
return in.length() == 1 ? "0" + in : in;
|
||||
}
|
||||
|
||||
public String toHexString() {
|
||||
var value = terminalColor;
|
||||
return "#" + (format(value.getRed()) + format(value.getGreen()) + format(value.getBlue()))
|
||||
.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class ApplicationHelper {
|
|||
processControl.getShellDialect().getWhichCommand(executable));
|
||||
}
|
||||
|
||||
public static void isInPath(
|
||||
public static void checkIsInPath(
|
||||
ShellControl processControl, String executable, String displayName, DataStoreEntry connection)
|
||||
throws Exception {
|
||||
if (!isInPath(processControl, executable)) {
|
||||
|
|
|
@ -3,27 +3,33 @@ package io.xpipe.app.util;
|
|||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.core.process.CommandControl;
|
||||
import io.xpipe.app.prefs.ExternalTerminalType;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.core.process.ProcessControl;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TerminalHelper {
|
||||
|
||||
public static void open(String title, CommandControl cc) throws Exception {
|
||||
public static void open(String title, ProcessControl cc) throws Exception {
|
||||
var command = cc.prepareTerminalOpen(title);
|
||||
open(title, command);
|
||||
open(null, title, cc);
|
||||
}
|
||||
|
||||
public static void open(String title, String command) throws Exception {
|
||||
public static void open(DataStoreEntry entry, String title, ProcessControl cc) throws Exception {
|
||||
var type = AppPrefs.get().terminalType().getValue();
|
||||
if (type == null) {
|
||||
throw ErrorEvent.unreportable(new IllegalStateException(AppI18n.get("noTerminalSet")));
|
||||
}
|
||||
|
||||
command = ScriptHelper.createLocalExecScript(command);
|
||||
|
||||
var prefix = entry != null && entry.getColor() != null && type.supportsColoredTitle()
|
||||
? entry.getColor().getEmoji() + " "
|
||||
: "";
|
||||
var fixedTitle = prefix + (title != null ? title : entry != null ? entry.getName() : "?");
|
||||
var file = ScriptHelper.createLocalExecScript(cc.prepareTerminalOpen(fixedTitle));
|
||||
var config = new ExternalTerminalType.LaunchConfiguration(entry != null ? entry.getColor() : null, title, file);
|
||||
try {
|
||||
type.launch(title, command);
|
||||
type.launch(config);
|
||||
} catch (Exception ex) {
|
||||
throw ErrorEvent.unreportable(new IOException(
|
||||
"Unable to launch terminal " + type.toTranslatedString() + ": " + ex.getMessage()
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
-fx-spacing: 0.8em;
|
||||
}
|
||||
|
||||
.store-header-bar > .top {
|
||||
-fx-font-weight: BOLD;
|
||||
}
|
||||
|
||||
.root.nord .store-header-bar {
|
||||
-fx-background-radius: 0;
|
||||
-fx-border-radius: 0;
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package io.xpipe.core.store;
|
||||
|
||||
import io.xpipe.core.process.ProcessControl;
|
||||
|
||||
public interface LaunchableStore extends DataStore {
|
||||
|
||||
default boolean canLaunch() {
|
||||
return true;
|
||||
}
|
||||
|
||||
String prepareLaunchCommand(String displayName) throws Exception;
|
||||
ProcessControl prepareLaunchCommand() throws Exception;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.xpipe.core.store;
|
||||
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.process.ShellDialect;
|
||||
|
||||
|
@ -18,8 +19,8 @@ public interface ShellStore extends DataStore, InternalCacheDataStore, Launchabl
|
|||
}
|
||||
|
||||
@Override
|
||||
default String prepareLaunchCommand(String displayName) throws Exception {
|
||||
return control().prepareTerminalOpen(displayName);
|
||||
default ProcessControl prepareLaunchCommand() throws Exception {
|
||||
return control();
|
||||
}
|
||||
|
||||
default ShellDialect getShellType() {
|
||||
|
|
|
@ -27,18 +27,17 @@ public class LaunchAction implements ActionProvider {
|
|||
public void execute() throws Exception {
|
||||
var storeName = entry.getName();
|
||||
if (entry.getStore() instanceof ShellStore s) {
|
||||
String command = ScriptStore.controlWithDefaultScripts(s.control()).prepareTerminalOpen(storeName);
|
||||
TerminalHelper.open(storeName, command);
|
||||
TerminalHelper.open(entry, storeName, ScriptStore.controlWithDefaultScripts(s.control()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.getStore() instanceof LaunchableStore s) {
|
||||
String command = s.prepareLaunchCommand(storeName);
|
||||
var command = s.prepareLaunchCommand();
|
||||
if (command == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TerminalHelper.open(storeName, command);
|
||||
TerminalHelper.open(entry, storeName, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public class XPipeUrlAction implements ActionProvider {
|
|||
public void execute() throws Exception {
|
||||
var storeName = entry.getName();
|
||||
if (entry.getStore() instanceof LaunchableStore s) {
|
||||
String command = s.prepareLaunchCommand(storeName);
|
||||
var command = s.prepareLaunchCommand();
|
||||
if (command == null) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ public class OpenTerminalAction implements LeafAction {
|
|||
if (model.getInOverview().get()) {
|
||||
TerminalHelper.open(
|
||||
model.getName(),
|
||||
model.getFileSystem().getShell().orElseThrow().prepareTerminalOpen(model.getName()));
|
||||
model.getFileSystem().getShell().orElseThrow());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue