Color improvements and terminal fixes

This commit is contained in:
crschnick 2023-10-07 16:33:01 +00:00
parent 993e1d5446
commit f277cc0a37
14 changed files with 243 additions and 182 deletions

View file

@ -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)));
}
});
});

View file

@ -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);

View file

@ -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();
}

View file

@ -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);
}
}

View 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 + "\""));
}
}
});

View file

@ -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();
}
}

View file

@ -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)) {

View file

@ -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()

View file

@ -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;

View file

@ -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;
}

View file

@ -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() {

View file

@ -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);
}
}
}

View file

@ -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;
}

View file

@ -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;
}