mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-26 01:20:28 +00:00
Rework default external application detection
This commit is contained in:
parent
538249637a
commit
5afee8120d
11 changed files with 306 additions and 154 deletions
|
@ -115,9 +115,9 @@ Furthermore, you also need the platform specific toolchains to be installed:
|
|||
|
||||
You can use the gradle wrapper to build and run the project:
|
||||
- `gradlew app:run` will run the desktop application. You can set various useful properties in `app/build.gradle`
|
||||
- `gradlew builtCli` will create a native image for the CLI application
|
||||
- `gradlew buildCli` will create a native image for the CLI application
|
||||
- `gradlew dist` will create a distributable production version in `dist/build/dist/base`.
|
||||
To include this CLI executable in this build, make sure to run `gradlew builtCli` first
|
||||
To include this CLI executable in this build, make sure to run `gradlew buildCli` first
|
||||
- You can also run the CLI application in development mode with something like `gradlew :cli:clean :cli:run --args="daemon start"`.
|
||||
Note here that you should always clean the CLI project first, as the native image plugin is a little buggy in that regard.
|
||||
- `gradlew <project>:test` will run the tests of the specified project.
|
||||
|
|
|
@ -181,7 +181,7 @@ public class EditorState {
|
|||
|
||||
public void openInEditor(String file) {
|
||||
var editor = AppPrefs.get().externalEditor().getValue();
|
||||
if (editor == null || !editor.isSupported()) {
|
||||
if (editor == null || !editor.isSelectable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,9 +61,9 @@ public class AppPrefs {
|
|||
private final ObjectProperty<SupportedLocale> languageInternal =
|
||||
typed(new SimpleObjectProperty<>(SupportedLocale.ENGLISH), SupportedLocale.class);
|
||||
public final Property<SupportedLocale> language = new SimpleObjectProperty<>(SupportedLocale.ENGLISH);
|
||||
private final SingleSelectionField<SupportedLocale> languageControl =
|
||||
Field.ofSingleSelectionType(languageList, languageInternal).render(() -> new TranslatableComboBoxControl<>());
|
||||
|
||||
private final SingleSelectionField<SupportedLocale> languageControl = Field.ofSingleSelectionType(
|
||||
languageList, languageInternal)
|
||||
.render(() -> new TranslatableComboBoxControl<>());
|
||||
|
||||
private final ObjectProperty<AppStyle.Theme> themeInternal =
|
||||
typed(new SimpleObjectProperty<>(AppStyle.Theme.LIGHT), AppStyle.Theme.class);
|
||||
|
@ -85,32 +85,36 @@ public class AppPrefs {
|
|||
|
||||
private final ObjectProperty<CloseBehaviour> closeBehaviour =
|
||||
typed(new SimpleObjectProperty<>(CloseBehaviour.QUIT), CloseBehaviour.class);
|
||||
private final SingleSelectionField<CloseBehaviour> closeBehaviourControl =
|
||||
Field.ofSingleSelectionType(closeBehaviourList, closeBehaviour).render(() -> new TranslatableComboBoxControl<>());
|
||||
private final ObjectProperty<ExternalEditorType> externalEditor =
|
||||
typed(new SimpleObjectProperty<>(ExternalEditorType.getDefault()), ExternalEditorType.class);
|
||||
private final SingleSelectionField<ExternalEditorType> externalEditorControl =
|
||||
Field.ofSingleSelectionType(externalEditorList, externalEditor).render(() -> new TranslatableComboBoxControl<>());
|
||||
private final SingleSelectionField<CloseBehaviour> closeBehaviourControl = Field.ofSingleSelectionType(
|
||||
closeBehaviourList, closeBehaviour)
|
||||
.render(() -> new TranslatableComboBoxControl<>());
|
||||
|
||||
// External editor
|
||||
// ===============
|
||||
private final StringProperty customEditorCommand = typed(new SimpleStringProperty(""), String.class);
|
||||
|
||||
final ObjectProperty<ExternalEditorType> externalEditor =
|
||||
typed(new SimpleObjectProperty<>(), ExternalEditorType.class);
|
||||
private final SingleSelectionField<ExternalEditorType> externalEditorControl = Field.ofSingleSelectionType(
|
||||
externalEditorList, externalEditor)
|
||||
.render(() -> new TranslatableComboBoxControl<>());
|
||||
|
||||
final StringProperty customEditorCommand = typed(new SimpleStringProperty(""), String.class);
|
||||
private final StringField customEditorCommandControl = editable(
|
||||
StringField.ofStringType(customEditorCommand).render(() -> new SimpleTextControl()),
|
||||
externalEditor.isEqualTo(ExternalEditorType.CUSTOM));
|
||||
private final IntegerProperty editorReloadTimeout = typed(new SimpleIntegerProperty(1000), Integer.class);
|
||||
private final ObjectProperty<ExternalStartupBehaviour> externalStartupBehaviour = typed(
|
||||
new SimpleObjectProperty<>(
|
||||
ExternalStartupBehaviour.TRAY.isSupported()
|
||||
ExternalStartupBehaviour.TRAY.isSelectable()
|
||||
? ExternalStartupBehaviour.TRAY
|
||||
: ExternalStartupBehaviour.BACKGROUND),
|
||||
ExternalStartupBehaviour.class);
|
||||
|
||||
|
||||
|
||||
private final SingleSelectionField<ExternalStartupBehaviour> externalStartupBehaviourControl =
|
||||
Field.ofSingleSelectionType(externalStartupBehaviourList, externalStartupBehaviour)
|
||||
.render(() -> new TranslatableComboBoxControl<>());
|
||||
// Automatically update
|
||||
// ====================
|
||||
private final BooleanProperty automaticallyUpdate =
|
||||
typed(new SimpleBooleanProperty(AppDistributionType.get().supportsUpdate()), Boolean.class);
|
||||
private final BooleanField automaticallyUpdateField = BooleanField.ofBooleanType(automaticallyUpdate)
|
||||
|
@ -135,8 +139,8 @@ public class AppPrefs {
|
|||
private final ObjectProperty<String> internalLogLevel =
|
||||
typed(new SimpleObjectProperty<>(DEFAULT_LOG_LEVEL), String.class);
|
||||
|
||||
// Automatically update
|
||||
// ====================
|
||||
// Log level
|
||||
// =========
|
||||
private final ObjectProperty<String> effectiveLogLevel = LOG_LEVEL_FIXED
|
||||
? new SimpleObjectProperty<>(System.getProperty(LOG_LEVEL_PROP).toLowerCase())
|
||||
: internalLogLevel;
|
||||
|
@ -144,6 +148,8 @@ public class AppPrefs {
|
|||
logLevelList, effectiveLogLevel)
|
||||
.editable(!LOG_LEVEL_FIXED)
|
||||
.render(() -> new SimpleComboBoxControl<>());
|
||||
// Developer mode
|
||||
// ==============
|
||||
private final BooleanProperty internalDeveloperMode = typed(new SimpleBooleanProperty(false), Boolean.class);
|
||||
private final BooleanProperty effectiveDeveloperMode = System.getProperty(DEVELOPER_MODE_PROP) != null
|
||||
? new SimpleBooleanProperty(Boolean.parseBoolean(System.getProperty(DEVELOPER_MODE_PROP)))
|
||||
|
@ -176,6 +182,70 @@ public class AppPrefs {
|
|||
developerDisableConnectorInstallationVersionCheck)
|
||||
.render(() -> new ToggleControl());
|
||||
|
||||
public ReadOnlyProperty<CloseBehaviour> closeBehaviour() {
|
||||
return closeBehaviour;
|
||||
}
|
||||
|
||||
public ReadOnlyProperty<ExternalEditorType> externalEditor() {
|
||||
return externalEditor;
|
||||
}
|
||||
|
||||
public ObservableValue<String> customEditorCommand() {
|
||||
return customEditorCommand;
|
||||
}
|
||||
|
||||
public final ReadOnlyIntegerProperty editorReloadTimeout() {
|
||||
return editorReloadTimeout;
|
||||
}
|
||||
|
||||
public ReadOnlyProperty<ExternalStartupBehaviour> externalStartupBehaviour() {
|
||||
return externalStartupBehaviour;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty automaticallyUpdate() {
|
||||
return automaticallyUpdate;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty updateToPrereleases() {
|
||||
return updateToPrereleases;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty confirmDeletions() {
|
||||
return confirmDeletions;
|
||||
}
|
||||
|
||||
public ObservableValue<Path> storageDirectory() {
|
||||
return effectiveStorageDirectory;
|
||||
}
|
||||
|
||||
public ReadOnlyProperty<String> logLevel() {
|
||||
return effectiveLogLevel;
|
||||
}
|
||||
|
||||
public ObservableValue<Boolean> developerMode() {
|
||||
return effectiveDeveloperMode;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty developerDisableUpdateVersionCheck() {
|
||||
return developerDisableUpdateVersionCheck;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty developerDisableGuiRestrictions() {
|
||||
return developerDisableGuiRestrictions;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty developerDisableConnectorInstallationVersionCheck() {
|
||||
return developerDisableConnectorInstallationVersionCheck;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty developerShowHiddenProviders() {
|
||||
return developerShowHiddenProviders;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty developerShowHiddenEntries() {
|
||||
return developerShowHiddenEntries;
|
||||
}
|
||||
|
||||
private AppPreferencesFx preferencesFx;
|
||||
private boolean controlsSetup;
|
||||
|
||||
|
@ -194,6 +264,8 @@ public class AppPrefs {
|
|||
public static void init() {
|
||||
INSTANCE = new AppPrefs();
|
||||
INSTANCE.preferencesFx.loadSettings();
|
||||
INSTANCE.initValues();
|
||||
PrefsProvider.getAll().forEach(prov -> prov.init());
|
||||
}
|
||||
|
||||
public static AppPrefs get() {
|
||||
|
@ -246,8 +318,11 @@ public class AppPrefs {
|
|||
save();
|
||||
}
|
||||
|
||||
// Log level
|
||||
// =========
|
||||
public void initValues() {
|
||||
if (externalEditor.get() == null) {
|
||||
ExternalEditorType.detectDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public void save() {
|
||||
preferencesFx.saveSettings();
|
||||
|
@ -257,76 +332,6 @@ public class AppPrefs {
|
|||
preferencesFx.discardChanges();
|
||||
}
|
||||
|
||||
public ReadOnlyProperty<CloseBehaviour> closeBehaviour() {
|
||||
return closeBehaviour;
|
||||
}
|
||||
|
||||
public ReadOnlyProperty<ExternalEditorType> externalEditor() {
|
||||
return externalEditor;
|
||||
}
|
||||
|
||||
public ObservableValue<String> customEditorCommand() {
|
||||
return customEditorCommand;
|
||||
}
|
||||
|
||||
public final ReadOnlyIntegerProperty editorReloadTimeout() {
|
||||
return editorReloadTimeout;
|
||||
}
|
||||
|
||||
public ReadOnlyProperty<ExternalStartupBehaviour> externalStartupBehaviour() {
|
||||
return externalStartupBehaviour;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty automaticallyUpdate() {
|
||||
return automaticallyUpdate;
|
||||
}
|
||||
|
||||
// Developer mode
|
||||
// ==============
|
||||
|
||||
public ReadOnlyBooleanProperty updateToPrereleases() {
|
||||
return updateToPrereleases;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty confirmDeletions() {
|
||||
return confirmDeletions;
|
||||
}
|
||||
|
||||
public ObservableValue<Path> storageDirectory() {
|
||||
return effectiveStorageDirectory;
|
||||
}
|
||||
|
||||
// Developer options
|
||||
// ====================
|
||||
|
||||
public ReadOnlyProperty<String> logLevel() {
|
||||
return effectiveLogLevel;
|
||||
}
|
||||
|
||||
public ObservableValue<Boolean> developerMode() {
|
||||
return effectiveDeveloperMode;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty developerDisableUpdateVersionCheck() {
|
||||
return developerDisableUpdateVersionCheck;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty developerDisableGuiRestrictions() {
|
||||
return developerDisableGuiRestrictions;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty developerDisableConnectorInstallationVersionCheck() {
|
||||
return developerDisableConnectorInstallationVersionCheck;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty developerShowHiddenProviders() {
|
||||
return developerShowHiddenProviders;
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty developerShowHiddenEntries() {
|
||||
return developerShowHiddenEntries;
|
||||
}
|
||||
|
||||
public Class<?> getSettingType(String breadcrumb) {
|
||||
var found = classMap.get(getSetting(breadcrumb).valueProperty());
|
||||
if (found == null) {
|
||||
|
@ -391,15 +396,15 @@ public class AppPrefs {
|
|||
Setting.of("useSystemFont", useSystemFontInternal),
|
||||
Setting.of("tooltipDelay", tooltipDelayInternal, tooltipDelayMin, tooltipDelayMax),
|
||||
Setting.of("fontSize", fontSizeInternal, fontSizeMin, fontSizeMax)),
|
||||
Group.of(
|
||||
"windowOptions",
|
||||
Setting.of("saveWindowLocation", saveWindowLocationInternal))),
|
||||
Group.of("windowOptions", Setting.of("saveWindowLocation", saveWindowLocationInternal))),
|
||||
Category.of(
|
||||
"integrations",
|
||||
Group.of(
|
||||
"editor",
|
||||
Setting.of("defaultProgram", externalEditorControl, externalEditor),
|
||||
Setting.of("customEditorCommand", customEditorCommandControl, customEditorCommand).applyVisibility( VisibilityProperty.of(externalEditor.isEqualTo(ExternalEditorType.CUSTOM))),
|
||||
Setting.of("customEditorCommand", customEditorCommandControl, customEditorCommand)
|
||||
.applyVisibility(VisibilityProperty.of(
|
||||
externalEditor.isEqualTo(ExternalEditorType.CUSTOM))),
|
||||
Setting.of(
|
||||
"editorReloadTimeout",
|
||||
editorReloadTimeout,
|
||||
|
|
|
@ -32,7 +32,7 @@ public enum CloseBehaviour implements PrefsChoiceValue {
|
|||
this.exit = exit;
|
||||
}
|
||||
|
||||
public boolean isSupported() {
|
||||
public boolean isSelectable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package io.xpipe.app.prefs;
|
|||
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellTypes;
|
||||
import io.xpipe.core.store.ShellStore;
|
||||
import io.xpipe.extension.prefs.PrefsChoiceValue;
|
||||
import io.xpipe.extension.util.ApplicationHelper;
|
||||
import io.xpipe.extension.util.WindowsRegistry;
|
||||
|
@ -11,7 +10,9 @@ import lombok.Getter;
|
|||
import org.apache.commons.lang3.SystemUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -20,13 +21,24 @@ import java.util.Optional;
|
|||
public abstract class ExternalEditorType implements PrefsChoiceValue {
|
||||
|
||||
public static final ExternalEditorType NOTEPAD = new WindowsFullPathType("app.notepad") {
|
||||
|
||||
@Override
|
||||
protected Optional<Path> determinePath() {
|
||||
return Optional.of(Path.of(System.getenv("SystemRoot") + "\\System32\\notepad.exe"));
|
||||
}
|
||||
};
|
||||
public static final ExternalEditorType NOTEPADPLUSPLUS_WINDOWS = new WindowsFullPathType("app.notepad++Windows") {
|
||||
|
||||
public static final ExternalEditorType VSCODE = new WindowsFullPathType("app.vscode") {
|
||||
|
||||
@Override
|
||||
protected Optional<Path> determinePath() {
|
||||
return Optional.of(Path.of(System.getenv("LOCALAPPDATA"))
|
||||
.resolve("Programs")
|
||||
.resolve("Microsoft VS Code")
|
||||
.resolve("bin")
|
||||
.resolve("code.cmd"));
|
||||
}
|
||||
};
|
||||
public static final ExternalEditorType NOTEPADPLUSPLUS_WINDOWS = new WindowsFullPathType("app.notepad++") {
|
||||
|
||||
@Override
|
||||
protected Optional<Path> determinePath() {
|
||||
|
@ -40,66 +52,80 @@ public abstract class ExternalEditorType implements PrefsChoiceValue {
|
|||
return launcherDir.map(Path::of);
|
||||
}
|
||||
};
|
||||
public static final ExternalEditorType NOTEPADPLUSPLUS_LINUX =
|
||||
new LinuxPathType("app.notepad++Linux", "notepad++") {};
|
||||
|
||||
public static final ExternalEditorType KATE = new LinuxPathType("app.kate", "kate") {};
|
||||
public static final PathType NOTEPADPLUSPLUS_LINUX = new PathType("app.notepad++", "notepad++");
|
||||
|
||||
public static final PathType VSCODE_LINUX = new PathType("app.vscode", "code");
|
||||
|
||||
public static final PathType KATE = new PathType("app.kate", "kate");
|
||||
|
||||
public static final PathType GEDIT = new PathType("app.gedit", "gedit");
|
||||
|
||||
public static final PathType LEAFPAD = new PathType("app.leafpad", "leafpad");
|
||||
|
||||
public static final PathType MOUSEPAD = new PathType("app.mousepad", "mousepad");
|
||||
|
||||
public static final PathType PLUMA = new PathType("app.pluma", "pluma");
|
||||
|
||||
public static final ExternalEditorType TEXT_EDIT = new MacOsFullPathType("app.textEdit") {
|
||||
@Override
|
||||
protected Path determinePath() {
|
||||
return Path.of("/Applications/TextEdit.app");
|
||||
}
|
||||
};
|
||||
|
||||
public static final ExternalEditorType NOTEPADPP_MACOS = new MacOsFullPathType("app.notepad++") {
|
||||
@Override
|
||||
protected Path determinePath() {
|
||||
return Path.of("/Applications/TextEdit.app");
|
||||
}
|
||||
};
|
||||
|
||||
public static final ExternalEditorType SUBLIME_MACOS = new MacOsFullPathType("app.sublime") {
|
||||
@Override
|
||||
protected Path determinePath() {
|
||||
return Path.of("/Applications/Sublime.app");
|
||||
}
|
||||
};
|
||||
|
||||
public static final ExternalEditorType VSCODE_MACOS = new MacOsFullPathType("app.vscode") {
|
||||
@Override
|
||||
protected Path determinePath() {
|
||||
return Path.of("/Applications/VSCode.app");
|
||||
}
|
||||
};
|
||||
|
||||
public static final ExternalEditorType CUSTOM = new ExternalEditorType("app.custom") {
|
||||
|
||||
@Override
|
||||
public void launch(Path file) throws IOException {
|
||||
var fileName = SystemUtils.IS_OS_WINDOWS ? " \"" + file + "\"" : file;
|
||||
var cmd = AppPrefs.get().customEditorCommand().getValue();
|
||||
var fullCmd = cmd + " " + fileName;
|
||||
Runtime.getRuntime()
|
||||
.exec(ShellTypes.getPlatformDefault()
|
||||
.executeCommandListWithShell(fullCmd)
|
||||
.toArray(String[]::new));
|
||||
public void launch(Path file) throws Exception {
|
||||
var customCommand = AppPrefs.get().customEditorCommand().getValue();
|
||||
if (customCommand == null || customCommand.trim().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var format = customCommand.contains("$file") ? customCommand : customCommand + " $file";
|
||||
var fileString = file.toString().contains(" ") ? "\"" + file + "\"" : file.toString();
|
||||
ApplicationHelper.executeLocalApplication(format.replace("$file",fileString));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
public boolean isSelectable() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static final ExternalEditorType TEXT_EDIT = new ExternalEditorType("app.textEdit") {
|
||||
|
||||
@Override
|
||||
public void launch(Path file) throws Exception {
|
||||
var fullCmd = "/Applications/TextEdit.app/Contents/MacOS/TextEdit \"" + file.toString() + "\"";
|
||||
ShellStore.withLocal(pc -> {
|
||||
pc.executeSimpleCommand(fullCmd);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return OsType.getLocal().equals(OsType.MAC);
|
||||
}
|
||||
};
|
||||
public static final List<ExternalEditorType> ALL =
|
||||
List.of(NOTEPAD, NOTEPADPLUSPLUS_WINDOWS, NOTEPADPLUSPLUS_LINUX, KATE, TEXT_EDIT, CUSTOM);
|
||||
private String id;
|
||||
|
||||
public static ExternalEditorType getDefault() {
|
||||
if (OsType.getLocal().equals(OsType.MAC)) {
|
||||
return TEXT_EDIT;
|
||||
}
|
||||
|
||||
return OsType.getLocal().equals(OsType.WINDOWS) ? NOTEPAD : KATE;
|
||||
}
|
||||
|
||||
public abstract void launch(Path file) throws Exception;
|
||||
|
||||
public abstract boolean isSupported();
|
||||
public abstract boolean isSelectable();
|
||||
|
||||
public abstract static class LinuxPathType extends ExternalEditorType {
|
||||
public static class PathType extends ExternalEditorType {
|
||||
|
||||
private final String command;
|
||||
|
||||
public LinuxPathType(String id, String command) {
|
||||
public PathType(String id, String command) {
|
||||
super(id);
|
||||
this.command = command;
|
||||
}
|
||||
|
@ -111,7 +137,7 @@ public abstract class ExternalEditorType implements PrefsChoiceValue {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
public boolean isSelectable() {
|
||||
return OsType.getLocal().equals(OsType.LINUX);
|
||||
}
|
||||
}
|
||||
|
@ -131,17 +157,103 @@ public abstract class ExternalEditorType implements PrefsChoiceValue {
|
|||
throw new IOException("Unable to find installation of " + getId());
|
||||
}
|
||||
|
||||
ApplicationHelper.executeLocalApplication(getCommand(path.get(), file));
|
||||
}
|
||||
|
||||
protected String getCommand(Path p, Path file) {
|
||||
var cmd = "\"" + p + "\"";
|
||||
return "start \"\" " + cmd + " \"" + file + "\"";
|
||||
ApplicationHelper.executeLocalApplication(List.of(path.get().toString(), file.toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
public boolean isSelectable() {
|
||||
return OsType.getLocal().equals(OsType.WINDOWS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
var path = determinePath();
|
||||
return path.isPresent() && Files.exists(path.get());
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class MacOsFullPathType extends ExternalEditorType {
|
||||
|
||||
public MacOsFullPathType(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
protected abstract Path determinePath();
|
||||
|
||||
@Override
|
||||
public void launch(Path file) throws Exception {
|
||||
var path = determinePath();
|
||||
ApplicationHelper.executeLocalApplication(List.of("open", path.toString(), file.toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelectable() {
|
||||
return OsType.getLocal().equals(OsType.MAC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
var path = determinePath();
|
||||
return Files.exists(path);
|
||||
}
|
||||
}
|
||||
|
||||
public static final List<ExternalEditorType> WINDOWS_EDITORS = List.of(VSCODE, NOTEPADPLUSPLUS_WINDOWS, NOTEPAD);
|
||||
public static final List<PathType> LINUX_EDITORS =
|
||||
List.of(VSCODE_LINUX, NOTEPADPLUSPLUS_LINUX, KATE, GEDIT, PLUMA, LEAFPAD, MOUSEPAD);
|
||||
public static final List<ExternalEditorType> MACOS_EDITORS =
|
||||
List.of(VSCODE_MACOS, SUBLIME_MACOS, NOTEPADPP_MACOS, TEXT_EDIT);
|
||||
|
||||
public static final List<ExternalEditorType> ALL = new ArrayList<>();
|
||||
static {
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
ALL.addAll(WINDOWS_EDITORS);
|
||||
}
|
||||
if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
ALL.addAll(LINUX_EDITORS);
|
||||
}
|
||||
if (OsType.getLocal().equals(OsType.MAC)) {
|
||||
ALL.addAll(MACOS_EDITORS);
|
||||
}
|
||||
ALL.add(CUSTOM);
|
||||
}
|
||||
|
||||
public static void detectDefault() {
|
||||
var typeProperty = AppPrefs.get().externalEditor;
|
||||
var customProperty = AppPrefs.get().customEditorCommand;
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
typeProperty.set(WINDOWS_EDITORS.stream()
|
||||
.filter(externalEditorType -> externalEditorType.isAvailable())
|
||||
.findFirst()
|
||||
.orElse(null));
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
var env = System.getenv("VISUAL");
|
||||
if (env != null) {
|
||||
var found = LINUX_EDITORS.stream()
|
||||
.filter(externalEditorType -> externalEditorType.command.equalsIgnoreCase(env))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (found == null) {
|
||||
typeProperty.set(CUSTOM);
|
||||
customProperty.set(env);
|
||||
} else {
|
||||
typeProperty.set(found);
|
||||
}
|
||||
} else {
|
||||
typeProperty.set(LINUX_EDITORS.stream()
|
||||
.filter(externalEditorType -> externalEditorType.isAvailable())
|
||||
.findFirst()
|
||||
.orElse(null));
|
||||
}
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.MAC)) {
|
||||
typeProperty.set(MACOS_EDITORS.stream()
|
||||
.filter(externalEditorType -> externalEditorType.isAvailable())
|
||||
.findFirst()
|
||||
.orElse(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ public enum ExternalStartupBehaviour implements PrefsChoiceValue {
|
|||
private final String id;
|
||||
private final OperationMode mode;
|
||||
|
||||
public boolean isSupported() {
|
||||
public boolean isSelectable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,8 @@ public interface ShellType {
|
|||
|
||||
List<String> executeCommandListWithShell(String cmd);
|
||||
|
||||
List<String> executeCommandListWithShell(List<String> cmd);
|
||||
|
||||
List<String> getMkdirsCommand(String dirs);
|
||||
|
||||
String getFileReadCommand(String file);
|
||||
|
|
|
@ -141,6 +141,14 @@ public class ShellTypes {
|
|||
return List.of("cmd", "/C", cmd.replaceAll("[\\^]", "^$0"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> executeCommandListWithShell(List<String> cmd) {
|
||||
var list = new ArrayList<String>();
|
||||
list.addAll(List.of("cmd", "/C"));
|
||||
list.addAll(cmd.stream().map(s -> s.replaceAll(" ", "^ ")).toList());
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMkdirsCommand(String dirs) {
|
||||
return List.of("(", "if", "not", "exist", dirs, "mkdir", dirs, ")");
|
||||
|
@ -230,6 +238,11 @@ public class ShellTypes {
|
|||
@Value
|
||||
public static class PowerShell implements ShellType {
|
||||
|
||||
@Override
|
||||
public List<String> executeCommandListWithShell(List<String> cmd) {
|
||||
return List.of("powershell", "-Command", flatten(cmd));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableHistory(ShellProcessControl pc) throws Exception {
|
||||
pc.executeLine("Set-PSReadLineOption -HistorySaveStyle SaveNothing");
|
||||
|
@ -416,6 +429,11 @@ public class ShellTypes {
|
|||
|
||||
public abstract static class PosixBase implements ShellType {
|
||||
|
||||
@Override
|
||||
public List<String> executeCommandListWithShell(List<String> cmd) {
|
||||
return List.of(getExecutable(), "-c", flatten(cmd));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitFileOpenCommand(String file) {
|
||||
return getName() + " --rcfile \"" + file + "\"";
|
||||
|
|
|
@ -39,11 +39,15 @@ public interface PrefsChoiceValue extends Translatable {
|
|||
throw new AssertionError();
|
||||
}
|
||||
|
||||
return all.stream().filter(t -> ((PrefsChoiceValue) t).isSupported()).toList();
|
||||
return all.stream().filter(t -> ((PrefsChoiceValue) t).isSelectable()).toList();
|
||||
}
|
||||
}
|
||||
|
||||
default boolean isSupported() {
|
||||
default boolean isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
default boolean isSelectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,4 +34,6 @@ public abstract class PrefsProvider {
|
|||
}
|
||||
|
||||
public abstract void addPrefs(PrefsHandler handler);
|
||||
|
||||
public abstract void init();
|
||||
}
|
||||
|
|
|
@ -2,18 +2,27 @@ package io.xpipe.extension.util;
|
|||
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellTypes;
|
||||
import io.xpipe.core.store.ShellStore;
|
||||
import io.xpipe.extension.event.TrackEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
public class ApplicationHelper {
|
||||
|
||||
public static void executeLocalApplication(String s) throws Exception {
|
||||
var args = ShellTypes.getPlatformDefault().executeCommandListWithShell(s);
|
||||
var p = new ProcessBuilder(args).redirectOutput(ProcessBuilder.Redirect.DISCARD).start();
|
||||
var error = new String(p.getErrorStream().readAllBytes(), StandardCharsets.UTF_8);
|
||||
if (p.waitFor() != 0) {
|
||||
throw new IOException(error);
|
||||
TrackEvent.withDebug("proc", "Executing local application").elements(args).handle();
|
||||
try (var c = ShellStore.local().create().command(s).start()) {
|
||||
c.discardOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
public static void executeLocalApplication(List<String> s) throws Exception {
|
||||
var args = ShellTypes.getPlatformDefault().executeCommandListWithShell(s);
|
||||
TrackEvent.withDebug("proc", "Executing local application").elements(args).handle();
|
||||
try (var c = ShellStore.local().create().command(s).start()) {
|
||||
c.discardOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue