diff --git a/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java b/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java index 221f6e533..966a31b16 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java @@ -43,6 +43,20 @@ public class IntegratedTextAreaComp extends Comp> host, Property value) { + var type = Bindings.createStringBinding( + () -> { + return host.getValue() != null + && host.getValue().getStore() instanceof StatefulDataStore sd + && sd.getState() instanceof SystemState ss + && ss.getShellDialect() != null + ? ss.getShellDialect().getScriptFileEnding() + : "sh"; + }, + host); + return script(value, type); + } + + public static IntegratedTextAreaComp script(Property value, ObservableValue fileType) { var string = new SimpleStringProperty(); value.subscribe(shellScript -> { string.set(shellScript != null ? shellScript.getValue() : null); @@ -54,16 +68,7 @@ public class IntegratedTextAreaComp extends Comp { - return host.getValue() != null - && host.getValue().getStore() instanceof StatefulDataStore sd - && sd.getState() instanceof SystemState ss - && ss.getShellDialect() != null - ? ss.getShellDialect().getScriptFileEnding() - : "sh"; - }, - host)); + fileType); return i; } diff --git a/app/src/main/java/io/xpipe/app/core/AppImages.java b/app/src/main/java/io/xpipe/app/core/AppImages.java index b698f7e79..8737f7738 100644 --- a/app/src/main/java/io/xpipe/app/core/AppImages.java +++ b/app/src/main/java/io/xpipe/app/core/AppImages.java @@ -40,6 +40,10 @@ public class AppImages { var exts = AppExtensionManager.getInstance().getContentModules(); for (Module ext : exts) { AppResources.with(ext.getName(), "img/", basePath -> { + if (!Files.exists(basePath)) { + return; + } + var skipLarge = AppDisplayScale.hasDefaultDisplayScale(); Files.walkFileTree(basePath, new SimpleFileVisitor<>() { @Override diff --git a/app/src/main/java/io/xpipe/app/process/ShellScript.java b/app/src/main/java/io/xpipe/app/process/ShellScript.java index 71c4114d1..0c0b9ade8 100644 --- a/app/src/main/java/io/xpipe/app/process/ShellScript.java +++ b/app/src/main/java/io/xpipe/app/process/ShellScript.java @@ -23,6 +23,15 @@ public class ShellScript { return new ShellScript(lines.stream().collect(Collectors.joining("\n"))); } + public String withoutShebang() { + var shebang = value.startsWith("#!"); + if (shebang) { + return value.lines().skip(1).collect(Collectors.joining("\n")); + } else { + return value; + } + } + @Override public String toString() { return value; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptStore.java b/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptStore.java index a5d533dc5..808ab634d 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptStore.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptStore.java @@ -2,7 +2,9 @@ package io.xpipe.ext.base.script; import io.xpipe.app.core.AppNames; import io.xpipe.app.core.AppResources; +import io.xpipe.app.process.ShellDialect; import io.xpipe.app.process.ShellDialects; +import io.xpipe.app.process.ShellScript; import io.xpipe.app.storage.DataStoreEntryRef; import lombok.Getter; @@ -18,34 +20,29 @@ import java.util.function.Supplier; public enum PredefinedScriptStore { APT_UPDATE("Apt upgrade", () -> SimpleScriptStore.builder() .group(PredefinedScriptGroup.MANAGEMENT.getEntry()) - .minimumDialect(ShellDialects.SH) - .commands(file(("apt_upgrade.sh"))) + .textSource(ScriptTextSource.InPlace.builder().dialect(ShellDialects.SH).text(file("apt_upgrade.sh")).build()) .shellScript(true) .runnableScript(true) .build()), REMOVE_CR("CRLF to LF", () -> SimpleScriptStore.builder() .group(PredefinedScriptGroup.FILES.getEntry()) - .minimumDialect(ShellDialects.SH) - .commands(file(("crlf_to_lf.sh"))) + .textSource(ScriptTextSource.InPlace.builder().dialect(ShellDialects.SH).text(file("crlf_to_lf.sh")).build()) .fileScript(true) .shellScript(true) .build()), DIFF("Diff", () -> SimpleScriptStore.builder() .group(PredefinedScriptGroup.FILES.getEntry()) - .minimumDialect(ShellDialects.SH) - .commands(file(("diff.sh"))) + .textSource(ScriptTextSource.InPlace.builder().dialect(ShellDialects.SH).text(file("diff.sh")).build()) .fileScript(true) .build()), GIT_CONFIG("Git Config", () -> SimpleScriptStore.builder() .group(PredefinedScriptGroup.MANAGEMENT.getEntry()) - .minimumDialect(null) - .commands(file(("git_config.sh"))) + .textSource(ScriptTextSource.InPlace.builder().text(file("git_config.sh")).build()) .runnableScript(true) .build()), SYSTEM_HEALTH_STATUS("System health status", () -> SimpleScriptStore.builder() .group(PredefinedScriptGroup.MANAGEMENT.getEntry()) - .minimumDialect(ShellDialects.SH) - .commands(file(("system_health.sh"))) + .textSource(ScriptTextSource.InPlace.builder().text(file("system_health.sh")).build()) .initScript(true) .build()); @@ -62,11 +59,11 @@ public enum PredefinedScriptStore { this.uuid = UUID.nameUUIDFromBytes(name.getBytes(StandardCharsets.UTF_8)); } - public static String file(String name) { + public static ShellScript file(String name) { AtomicReference string = new AtomicReference<>(); AppResources.with(AppNames.extModuleName("base"), "scripts/" + name, var1 -> { string.set(Files.readString(var1)); }); - return string.get(); + return ShellScript.of(string.get()); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSource.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSource.java similarity index 85% rename from ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSource.java rename to ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSource.java index 14df281b9..9e43fe714 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSource.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSource.java @@ -7,12 +7,9 @@ import io.xpipe.app.comp.base.ContextualFileReferenceChoiceComp; import io.xpipe.app.core.AppCache; import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.ProcessControlProvider; -import io.xpipe.app.ext.ShellDialectChoiceComp; import io.xpipe.app.ext.ValidationException; -import io.xpipe.app.icon.SystemIconSource; import io.xpipe.app.issue.ErrorEventFactory; import io.xpipe.app.platform.OptionsBuilder; -import io.xpipe.app.process.ShellDialects; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.util.Validators; import io.xpipe.core.FilePath; @@ -32,16 +29,16 @@ import java.util.List; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes({ - @JsonSubTypes.Type(value = ScriptSource.Directory.class), - @JsonSubTypes.Type(value = ScriptSource.GitRepository.class) + @JsonSubTypes.Type(value = ScriptCollectionSource.Directory.class), + @JsonSubTypes.Type(value = ScriptCollectionSource.GitRepository.class) }) -public interface ScriptSource { +public interface ScriptCollectionSource { @JsonTypeName("directory") @Value @Jacksonized @Builder - class Directory implements ScriptSource { + class Directory implements ScriptCollectionSource { Path path; @@ -92,7 +89,7 @@ public interface ScriptSource { @Value @Jacksonized @Builder - class GitRepository implements ScriptSource { + class GitRepository implements ScriptCollectionSource { String url; @@ -157,16 +154,9 @@ public interface ScriptSource { String toName(); - default List listScripts() throws Exception { - var availableDialects = List.of( - ShellDialects.SH, - ShellDialects.BASH, - ShellDialects.ZSH, - ShellDialects.FISH, - ShellDialects.CMD, - ShellDialects.POWERSHELL, - ShellDialects.POWERSHELL_CORE); - var l = new ArrayList(); + default List listScripts() throws Exception { + var availableDialects = ScriptDialects.getSupported(); + var l = new ArrayList(); Files.walkFileTree(getLocalPath(), new SimpleFileVisitor<>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { @@ -178,9 +168,9 @@ public interface ScriptSource { return FileVisitResult.CONTINUE; } - var entry = ScriptSourceEntry.builder() + var entry = ScriptCollectionSourceEntry.builder() .name(name) - .source(ScriptSource.this) + .source(ScriptCollectionSource.this) .dialect(dialect.get()) .localFile(file) .build(); diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceBrowseActionProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceBrowseActionProvider.java similarity index 61% rename from ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceBrowseActionProvider.java rename to ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceBrowseActionProvider.java index b667c38a7..590f1227b 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceBrowseActionProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceBrowseActionProvider.java @@ -1,24 +1,20 @@ package io.xpipe.ext.base.script; import io.xpipe.app.action.AbstractAction; -import io.xpipe.app.browser.BrowserFullSessionModel; import io.xpipe.app.core.AppI18n; -import io.xpipe.app.ext.FileSystemStore; import io.xpipe.app.hub.action.HubLeafProvider; import io.xpipe.app.hub.action.StoreAction; import io.xpipe.app.platform.LabelGraphic; -import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.app.util.DesktopHelper; -import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ObservableValue; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; -public class ScriptSourceBrowseActionProvider implements HubLeafProvider { +public class ScriptCollectionSourceBrowseActionProvider implements HubLeafProvider { @Override - public AbstractAction createAction(DataStoreEntryRef ref) { + public AbstractAction createAction(DataStoreEntryRef ref) { return Action.builder().ref(ref).build(); } @@ -28,28 +24,28 @@ public class ScriptSourceBrowseActionProvider implements HubLeafProvider getName(DataStoreEntryRef store) { + public ObservableValue getName(DataStoreEntryRef store) { return AppI18n.observable("browse"); } @Override - public LabelGraphic getIcon(DataStoreEntryRef store) { + public LabelGraphic getIcon(DataStoreEntryRef store) { return new LabelGraphic.IconGraphic("mdi2f-folder-search-outline"); } @Override - public Class getApplicableClass() { - return ScriptSourceStore.class; + public Class getApplicableClass() { + return ScriptCollectionSourceStore.class; } @Override public String getId() { - return "browseScriptSource"; + return "browseScriptCollectionSource"; } @Jacksonized @SuperBuilder - public static class Action extends StoreAction { + public static class Action extends StoreAction { @Override public void executeImpl() { diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceEntry.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceEntry.java similarity index 78% rename from ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceEntry.java rename to ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceEntry.java index d78d81c22..d471684c4 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceEntry.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceEntry.java @@ -10,10 +10,10 @@ import java.nio.file.Path; @Value @Builder @Jacksonized -public class ScriptSourceEntry { +public class ScriptCollectionSourceEntry { String name; ShellDialect dialect; - ScriptSource source; + ScriptCollectionSource source; Path localFile; } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceRefreshHubProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceRefreshHubProvider.java similarity index 67% rename from ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceRefreshHubProvider.java rename to ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceRefreshHubProvider.java index 2fc57d0f4..fe3d6ecb1 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceRefreshHubProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceRefreshHubProvider.java @@ -1,20 +1,16 @@ package io.xpipe.ext.base.script; import io.xpipe.app.core.AppI18n; -import io.xpipe.app.ext.FixedHierarchyStore; -import io.xpipe.app.hub.action.BatchHubProvider; import io.xpipe.app.hub.action.HubLeafProvider; import io.xpipe.app.hub.action.StoreAction; import io.xpipe.app.hub.action.StoreActionCategory; import io.xpipe.app.platform.LabelGraphic; -import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntryRef; -import io.xpipe.ext.base.service.FixedServiceGroupStore; import javafx.beans.value.ObservableValue; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; -public class ScriptSourceRefreshHubProvider implements HubLeafProvider { +public class ScriptCollectionSourceRefreshHubProvider implements HubLeafProvider { @Override public StoreActionCategory getCategory() { @@ -27,28 +23,28 @@ public class ScriptSourceRefreshHubProvider implements HubLeafProvider getName(DataStoreEntryRef store) { + public ObservableValue getName(DataStoreEntryRef store) { return AppI18n.observable("refreshSource"); } @Override - public LabelGraphic getIcon(DataStoreEntryRef store) { + public LabelGraphic getIcon(DataStoreEntryRef store) { return new LabelGraphic.IconGraphic("mdi2r-refresh"); } @Override public Class getApplicableClass() { - return ScriptSourceStore.class; + return ScriptCollectionSourceStore.class; } @Override public String getId() { - return "refreshSource"; + return "refreshScriptCollection"; } @Jacksonized @SuperBuilder - public static class Action extends StoreAction { + public static class Action extends StoreAction { @Override public void executeImpl() throws Exception { diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceStore.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceStore.java similarity index 65% rename from ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceStore.java rename to ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceStore.java index 5445bc510..76b840544 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceStore.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceStore.java @@ -1,17 +1,8 @@ package io.xpipe.ext.base.script; -import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeName; import io.xpipe.app.ext.*; -import io.xpipe.app.process.ShellStoreState; -import io.xpipe.app.storage.DataStorage; -import io.xpipe.app.storage.DataStoreEntryRef; -import io.xpipe.app.util.HostHelper; -import io.xpipe.app.util.LicenseProvider; import io.xpipe.app.util.Validators; -import io.xpipe.ext.base.host.HostAddressGatewayStore; -import io.xpipe.ext.base.service.ServiceAddressRotation; -import io.xpipe.ext.base.service.ServiceProtocolType; import lombok.*; import lombok.experimental.FieldDefaults; import lombok.experimental.SuperBuilder; @@ -22,10 +13,10 @@ import java.util.List; @SuperBuilder(toBuilder = true) @Value @Jacksonized -@JsonTypeName("scriptSource") -public class ScriptSourceStore implements DataStore, StatefulDataStore { +@JsonTypeName("scriptCollectionSource") +public class ScriptCollectionSourceStore implements DataStore, StatefulDataStore { - ScriptSource source; + ScriptCollectionSource source; @Override public void checkComplete() throws Throwable { @@ -46,7 +37,7 @@ public class ScriptSourceStore implements DataStore, StatefulDataStore entries; + List entries; @Override public DataStoreState mergeCopy(DataStoreState newer) { diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceStoreProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceStoreProvider.java similarity index 67% rename from ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceStoreProvider.java rename to ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceStoreProvider.java index 798003678..131e80804 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptSourceStoreProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceStoreProvider.java @@ -1,40 +1,24 @@ package io.xpipe.ext.base.script; import io.xpipe.app.comp.Comp; -import io.xpipe.app.comp.base.IntegratedTextAreaComp; -import io.xpipe.app.comp.base.ListSelectorComp; -import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.*; import io.xpipe.app.hub.comp.*; import io.xpipe.app.platform.OptionsBuilder; import io.xpipe.app.platform.OptionsChoiceBuilder; -import io.xpipe.app.platform.Validator; -import io.xpipe.app.process.OsFileSystem; -import io.xpipe.app.process.ShellDialect; -import io.xpipe.app.process.ShellDialects; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreCategory; import io.xpipe.app.storage.DataStoreEntry; -import io.xpipe.app.util.DataStoreFormatter; import io.xpipe.app.util.DocumentationLink; -import io.xpipe.core.OsType; import javafx.beans.binding.Bindings; import javafx.beans.property.Property; -import javafx.beans.property.SimpleListProperty; import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; import lombok.SneakyThrows; -import java.util.ArrayList; import java.util.List; -import java.util.Locale; import java.util.UUID; -import java.util.function.Function; -import java.util.stream.Stream; -public class ScriptSourceStoreProvider implements DataStoreProvider { +public class ScriptCollectionSourceStoreProvider implements DataStoreProvider { @Override public UUID getTargetCategory(DataStore store, UUID target) { @@ -69,18 +53,18 @@ public class ScriptSourceStoreProvider implements DataStoreProvider { @SneakyThrows @Override public GuiDialog guiDialog(DataStoreEntry entry, Property store) { - ScriptSourceStore st = store.getValue().asNeeded(); + ScriptCollectionSourceStore st = store.getValue().asNeeded(); var source = new SimpleObjectProperty<>(st.getSource()); - var sourceChoice = OptionsChoiceBuilder.builder().property(source).available(ScriptSource.getClasses()).build(); + var sourceChoice = OptionsChoiceBuilder.builder().property(source).available(ScriptCollectionSource.getClasses()).build(); return new OptionsBuilder() - .nameAndDescription("scriptSourceType") + .nameAndDescription("scriptCollectionSourceType") .sub(sourceChoice.build(), source) .bind( () -> { - return ScriptSourceStore.builder().source(source.get()).build(); + return ScriptCollectionSourceStore.builder().source(source.get()).build(); }, store) .buildDialog(); @@ -88,13 +72,13 @@ public class ScriptSourceStoreProvider implements DataStoreProvider { @Override public String summaryString(StoreEntryWrapper wrapper) { - ScriptSourceStore st = wrapper.getEntry().getStore().asNeeded(); + ScriptCollectionSourceStore st = wrapper.getEntry().getStore().asNeeded(); return st.getSource().toName(); } @Override public ObservableValue informationString(StoreSection section) { - ScriptSourceStore st = section.getWrapper().getEntry().getStore().asNeeded(); + ScriptCollectionSourceStore st = section.getWrapper().getEntry().getStore().asNeeded(); return Bindings.createStringBinding(() -> { var s = st.getState(); var summary = st.getSource().toSummary(); @@ -104,16 +88,16 @@ public class ScriptSourceStoreProvider implements DataStoreProvider { @Override public DataStore defaultStore(DataStoreCategory category) { - return ScriptSourceStore.builder().build(); + return ScriptCollectionSourceStore.builder().build(); } @Override public String getId() { - return "scriptSource"; + return "scriptCollectionSource"; } @Override public List> getStoreClasses() { - return List.of(ScriptSourceStore.class); + return List.of(ScriptCollectionSourceStore.class); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptDialects.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptDialects.java new file mode 100644 index 000000000..ed1c3c645 --- /dev/null +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptDialects.java @@ -0,0 +1,21 @@ +package io.xpipe.ext.base.script; + +import io.xpipe.app.process.ShellDialect; +import io.xpipe.app.process.ShellDialects; + +import java.util.List; + +public class ScriptDialects { + + public static List getSupported() { + var availableDialects = List.of( + ShellDialects.SH, + ShellDialects.BASH, + ShellDialects.ZSH, + ShellDialects.FISH, + ShellDialects.CMD, + ShellDialects.POWERSHELL, + ShellDialects.POWERSHELL_CORE); + return availableDialects; + } +} diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStoreSetup.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStoreSetup.java index c23ecec02..8c561cef7 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStoreSetup.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStoreSetup.java @@ -71,7 +71,7 @@ public class ScriptStoreSetup { pc.withInitSnippet( new ShellTerminalInitCommand() { - String dir; + FilePath dir; @Override public Optional terminalContent(ShellControl shellControl) throws Exception { @@ -84,7 +84,7 @@ public class ScriptStoreSetup { } return Optional.ofNullable( - shellControl.getShellDialect().addToPathVariableCommand(List.of(dir), true)); + shellControl.getShellDialect().addToPathVariableCommand(List.of(dir.toString()), true)); } @Override @@ -102,14 +102,14 @@ public class ScriptStoreSetup { } } - private static String initScriptsDirectory(ShellControl proc, List> refs) + private static FilePath initScriptsDirectory(ShellControl sc, List> refs) throws Exception { if (refs.isEmpty()) { return null; } var applicable = refs.stream() - .filter(simpleScriptStore -> simpleScriptStore.getStore().isCompatible(proc.getShellDialect())) + .filter(simpleScriptStore -> simpleScriptStore.getStore().isCompatible(sc.getShellDialect())) .toList(); if (applicable.isEmpty()) { return null; @@ -119,13 +119,11 @@ public class ScriptStoreSetup { .mapToInt(value -> value.get().getName().hashCode() + value.getStore().hashCode()) .sum(); - var targetDir = ShellTemp.createUserSpecificTempDataDirectory(proc, "scripts") - .join(proc.getShellDialect().getId()) - .toString(); - var hashFile = FilePath.of(targetDir, "hash"); - var d = proc.getShellDialect(); - if (d.createFileExistsCommand(proc, hashFile.toString()).executeAndCheck()) { - var read = d.getFileReadCommand(proc, hashFile.toString()).readStdoutOrThrow(); + var targetDir = ShellTemp.createUserSpecificTempDataDirectory(sc, "scripts") + .join(sc.getShellDialect().getId()); + var hashFile = targetDir.join("hash"); + if (sc.view().fileExists(hashFile)) { + var read = sc.view().readTextFile(hashFile); try { var readHash = Integer.parseInt(read); if (hash == readHash) { @@ -136,21 +134,23 @@ public class ScriptStoreSetup { } } - if (d.directoryExists(proc, targetDir).executeAndCheck()) { - d.deleteFileOrDirectory(proc, targetDir).execute(); + if (sc.view().directoryExists(targetDir)) { + sc.view().deleteDirectory(targetDir); } - proc.executeSimpleCommand(d.getMkdirsCommand(targetDir)); + sc.view().mkdir(targetDir); + var d = sc.getShellDialect(); for (DataStoreEntryRef scriptStore : refs) { - var content = d.prepareScriptContent(proc, scriptStore.getStore().getCommands()); - var fileName = OsFileSystem.of(proc.getOsType()) + var src = scriptStore.getStore().getTextSource(); + var content = src.getText(); + var fileName = OsFileSystem.of(sc.getOsType()) .makeFileSystemCompatible( scriptStore.get().getName().toLowerCase(Locale.ROOT).replaceAll(" ", "_")); - var scriptFile = FilePath.of(targetDir, fileName + "." + d.getScriptFileEnding()); - proc.view().writeScriptFile(scriptFile, content); + var scriptFile = targetDir.join(fileName + "." + d.getScriptFileEnding()); + sc.view().writeScriptFile(scriptFile, content.getValue()); } - proc.view().writeTextFile(hashFile, String.valueOf(hash)); + sc.view().writeTextFile(hashFile, String.valueOf(hash)); return targetDir; } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptTextSource.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptTextSource.java new file mode 100644 index 000000000..f36a5e4f9 --- /dev/null +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptTextSource.java @@ -0,0 +1,241 @@ +package io.xpipe.ext.base.script; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import io.xpipe.app.comp.Comp; +import io.xpipe.app.comp.base.ContextualFileReferenceChoiceComp; +import io.xpipe.app.comp.base.IntegratedTextAreaComp; +import io.xpipe.app.core.AppCache; +import io.xpipe.app.core.AppI18n; +import io.xpipe.app.ext.ProcessControlProvider; +import io.xpipe.app.ext.ShellDialectChoiceComp; +import io.xpipe.app.ext.ValidationException; +import io.xpipe.app.issue.ErrorEventFactory; +import io.xpipe.app.platform.OptionsBuilder; +import io.xpipe.app.process.ShellDialect; +import io.xpipe.app.process.ShellScript; +import io.xpipe.app.storage.DataStorage; +import io.xpipe.app.util.DocumentationLink; +import io.xpipe.app.util.HttpHelper; +import io.xpipe.app.util.Validators; +import io.xpipe.core.FilePath; +import io.xpipe.core.UuidHelper; +import javafx.beans.binding.Bindings; +import javafx.beans.property.Property; +import javafx.beans.property.ReadOnlyObjectWrapper; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import lombok.Builder; +import lombok.SneakyThrows; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") +@JsonSubTypes({ + @JsonSubTypes.Type(value = ScriptTextSource.InPlace.class), + @JsonSubTypes.Type(value = ScriptTextSource.Url.class), + @JsonSubTypes.Type(value = ScriptTextSource.SourceReference.class) +}) +public interface ScriptTextSource { + + @JsonTypeName("inPlace") + @Value + @Jacksonized + @Builder + class InPlace implements ScriptTextSource { + + ShellDialect dialect; + ShellScript text; + + @SuppressWarnings("unused") + public static String getOptionsNameKey() { + return "scriptSourceTypeInPlace"; + } + + @SuppressWarnings("unused") + static OptionsBuilder createOptions(Property property) { + var dialect = new SimpleObjectProperty<>(property.getValue().getDialect()); + var text = new SimpleObjectProperty<>(property.getValue().getText()); + + var availableDialects = ScriptDialects.getSupported(); + var choice = new ShellDialectChoiceComp(availableDialects, dialect, ShellDialectChoiceComp.NullHandling.NULL_IS_ALL); + + return new OptionsBuilder() + .name("minimumShellDialect") + .description("minimumShellDialectDescription") + .documentationLink(DocumentationLink.SCRIPTING_COMPATIBILITY) + .addComp(choice, dialect) + .name("scriptContents") + .description("scriptContentsDescription") + .documentationLink(DocumentationLink.SCRIPTING_EDITING) + .addComp(IntegratedTextAreaComp.script(text, Bindings.createStringBinding(() -> { + return dialect.getValue() != null + ? dialect.getValue().getScriptFileEnding() + : "sh"; + }, dialect))) + .bind(() -> InPlace.builder().dialect(dialect.get()).text(text.get()).build(), + property); + } + + @Override + public void checkComplete() throws ValidationException { + Validators.nonNull(text); + } + + @Override + public String toSummary() { + return dialect.getDisplayName(); + } + } + + @JsonTypeName("url") + @Value + @Jacksonized + @Builder + class Url implements ScriptTextSource { + + ShellDialect dialect; + String url; + ShellScript lastText; + + @SuppressWarnings("unused") + public static String getOptionsNameKey() { + return "scriptSourceTypeUrl"; + } + + @SuppressWarnings("unused") + static OptionsBuilder createOptions(Property property) { + var dialect = new SimpleObjectProperty<>(property.getValue().getDialect()); + var url = new SimpleStringProperty(property.getValue().getUrl()); + + var availableDialects = ScriptDialects.getSupported(); + var choice = new ShellDialectChoiceComp(availableDialects, dialect, ShellDialectChoiceComp.NullHandling.NULL_IS_ALL); + + return new OptionsBuilder() + .name("minimumShellDialect") + .description("minimumShellDialectDescription") + .documentationLink(DocumentationLink.SCRIPTING_COMPATIBILITY) + .addComp(choice, dialect) + .nameAndDescription("scriptTextSourceUrl").addString(url).nonNull().bind( + () -> Url.builder().dialect(dialect.get()).url(url.get()).build(), property); + } + + private void prepare() throws Exception { + var path = getLocalPath(); + if (Files.exists(path)) { + return; + } + + var req = HttpRequest.newBuilder().GET().uri(URI.create(url)).build(); + var r = HttpHelper.client().send(req, HttpResponse.BodyHandlers.ofString()); + if (r.statusCode() >= 400) { + throw ErrorEventFactory.expected(new IOException(r.body())); + } + + Files.writeString(path, r.body()); + } + + private Path getLocalPath() { + return AppCache.getBasePath().resolve("scripts").resolve(getName()); + } + + private String getName() { + var name = FilePath.of(url).getFileName(); + if (!name.isEmpty()) { + return name; + } + + return UuidHelper.generateFromObject(url).toString(); + } + + @Override + public void checkComplete() throws ValidationException { + Validators.nonNull(url); + Validators.nonNull(lastText); + } + + @Override + public String toSummary() { + return url; + } + + @Override + @SneakyThrows + public ShellScript getText() { + return lastText; + } + } + + @JsonTypeName("source") + @Value + @Jacksonized + @Builder + class SourceReference implements ScriptTextSource { + + ScriptCollectionSourceEntry entry; + + @SuppressWarnings("unused") + public static String getOptionsNameKey() { + return "scriptSourceTypeSource"; + } + + @SuppressWarnings("unused") + static OptionsBuilder createOptions(Property property) { + var entry = new SimpleObjectProperty<>(property.getValue().getEntry()); + + return new OptionsBuilder().bind( + () -> SourceReference.builder().entry(entry.get()).build(), property); + } + + @Override + public void checkComplete() throws ValidationException { + Validators.nonNull(entry); + entry.getSource().checkComplete(); + } + + @Override + public String toSummary() { + return entry.getName(); + } + + @Override + public ShellDialect getDialect() { + return entry.getDialect(); + } + + @Override + @SneakyThrows + public ShellScript getText() { + var r = Files.readString(entry.getLocalFile()); + return ShellScript.of(r); + } + } + + void checkComplete() throws ValidationException; + + String toSummary(); + + ShellDialect getDialect(); + + ShellScript getText(); + + static List> getClasses() { + var l = new ArrayList>(); + l.add(InPlace.class); + l.add(Url.class); + l.add(SourceReference.class); + return l; + } +} diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptMigrationDeserializer.java b/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptMigrationDeserializer.java new file mode 100644 index 000000000..74c353c89 --- /dev/null +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptMigrationDeserializer.java @@ -0,0 +1,69 @@ +package io.xpipe.ext.base.script; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer; +import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; +import com.fasterxml.jackson.databind.node.TreeTraversingParser; +import io.xpipe.app.storage.DataStorage; + +import java.io.IOException; + +public class SimpleScriptMigrationDeserializer extends DelegatingDeserializer { + + public SimpleScriptMigrationDeserializer(JsonDeserializer d) { + super(d); + } + + @Override + protected JsonDeserializer newDelegatingInstance(JsonDeserializer newDelegatee) { + return new SimpleScriptMigrationDeserializer(newDelegatee); + } + + @Override + public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + return super.deserialize(restructure(p), ctxt); + } + + @Override + public Object deserialize(JsonParser p, DeserializationContext ctxt, Object intoValue) throws IOException { + return super.deserialize(restructure(p), ctxt, intoValue); + } + + public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer typeDeserializer) + throws IOException { + return super.deserializeWithType(restructure(jp), ctxt, typeDeserializer); + } + + public JsonParser restructure(JsonParser p) throws IOException { + var node = p.readValueAsTree(); + if (node == null || !node.isObject()) { + return p; + } + + migrate((ObjectNode) node); + var newJsonParser = new TreeTraversingParser(((ObjectNode) node), p.getCodec()); + newJsonParser.nextToken(); + return newJsonParser; + } + + private void migrate(ObjectNode n) { + var commandsNode = n.remove("commands"); + var dialectNode = n.remove("minimumDialect"); + + var obj = JsonNodeFactory.instance.objectNode(); + obj.put("type", "inPlace"); + obj.put("text", commandsNode.textValue()); + if (!dialectNode.isNull()) { + obj.put("dialect", dialectNode.textValue()); + } else { + obj.putNull("dialect"); + } + + n.set("textSource", obj); + } +} diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptQuickEditHubLeafProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptQuickEditHubLeafProvider.java index 72da58717..e504e5686 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptQuickEditHubLeafProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptQuickEditHubLeafProvider.java @@ -8,6 +8,7 @@ import io.xpipe.app.hub.action.StoreActionCategory; import io.xpipe.app.hub.comp.StoreCreationDialog; import io.xpipe.app.platform.LabelGraphic; import io.xpipe.app.process.OsFileSystem; +import io.xpipe.app.process.ShellScript; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.app.util.FileOpener; @@ -75,14 +76,20 @@ public class SimpleScriptQuickEditHubLeafProvider implements HubLeafProvider { + FileOpener.openString(name + "." + ext, this, script.getTextSource().getText().getValue(), (s) -> { DataStorage.get() .updateEntryStore( - ref.get(), script.toBuilder().commands(s).build()); + ref.get(), script.toBuilder().textSource(ScriptTextSource.InPlace.builder().dialect(dialect).text(ShellScript.of(s)).build()).build()); }); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptStore.java b/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptStore.java index bd92ab28b..936ae33aa 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptStore.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptStore.java @@ -29,37 +29,30 @@ import java.util.stream.Collectors; @ToString(callSuper = true) public class SimpleScriptStore extends ScriptStore implements SelfReferentialStore { - ShellDialect minimumDialect; - String commands; + ScriptTextSource textSource; boolean initScript; boolean shellScript; boolean fileScript; boolean runnableScript; - public String getCommands() { - return commands != null ? commands : ""; + public ShellDialect getMinimumDialect() { + return textSource != null ? textSource.getDialect() : null; } public boolean isCompatible(ShellControl shellControl) { var targetType = shellControl.getOriginalShellDialect(); - return minimumDialect == null || minimumDialect.isCompatibleTo(targetType); + return getMinimumDialect() == null || getMinimumDialect().isCompatibleTo(targetType); } public boolean isCompatible(ShellDialect dialect) { - return minimumDialect == null || minimumDialect.isCompatibleTo(dialect); + return getMinimumDialect() == null || getMinimumDialect().isCompatibleTo(dialect); } private String assembleScript(ShellControl shellControl, boolean args) { if (isCompatible(shellControl)) { - var shebang = getCommands().startsWith("#"); - // Fix new lines and shebang - var fixedCommands = getCommands() - .lines() - .skip(shebang ? 1 : 0) - .collect(Collectors.joining( - shellControl.getShellDialect().getNewLine().getNewLineString())); + var raw = getTextSource().getText().withoutShebang(); var targetType = shellControl.getOriginalShellDialect(); - var script = ScriptHelper.createExecScript(targetType, shellControl, fixedCommands); + var script = ScriptHelper.createExecScript(targetType, shellControl, raw); return targetType.sourceScriptCommand(shellControl, script.toString()) + (args ? " " + targetType.getCatchAllVariable() : ""); } @@ -82,6 +75,7 @@ public class SimpleScriptStore extends ScriptStore implements SelfReferentialSto @Override public void checkComplete() throws Throwable { + Validators.nonNull(textSource); Validators.nonNull(group); super.checkComplete(); if (!initScript && !shellScript && !fileScript && !runnableScript) { diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptStoreProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptStoreProvider.java index 37d09cc60..385a4a90b 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptStoreProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptStoreProvider.java @@ -7,6 +7,7 @@ import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.*; import io.xpipe.app.hub.comp.*; import io.xpipe.app.platform.OptionsBuilder; +import io.xpipe.app.platform.OptionsChoiceBuilder; import io.xpipe.app.platform.Validator; import io.xpipe.app.process.OsFileSystem; import io.xpipe.app.process.ShellDialect; @@ -75,22 +76,11 @@ public class SimpleScriptStoreProvider implements EnabledParentStoreProvider, Da public GuiDialog guiDialog(DataStoreEntry entry, Property store) { SimpleScriptStore st = store.getValue().asNeeded(); + var textSource = new SimpleObjectProperty<>(st.getTextSource()); var group = new SimpleObjectProperty<>(st.getGroup()); - Property dialect = new SimpleObjectProperty<>(st.getMinimumDialect()); - var others = - new SimpleListProperty<>(FXCollections.observableArrayList(new ArrayList<>(st.getEffectiveScripts()))); - Property commandProp = new SimpleObjectProperty<>(st.getCommands()); + var others = new SimpleListProperty<>(FXCollections.observableArrayList(new ArrayList<>(st.getEffectiveScripts()))); - var availableDialects = List.of( - ShellDialects.SH, - ShellDialects.BASH, - ShellDialects.ZSH, - ShellDialects.FISH, - ShellDialects.CMD, - ShellDialects.POWERSHELL, - ShellDialects.POWERSHELL_CORE); - Comp choice = - new ShellDialectChoiceComp(availableDialects, dialect, ShellDialectChoiceComp.NullHandling.NULL_IS_ALL); + var textSourceChoice = OptionsChoiceBuilder.builder().property(textSource).available(ScriptTextSource.getClasses()).build(); var vals = List.of(0, 1, 2, 3); var selectedStart = new ArrayList(); @@ -134,20 +124,9 @@ public class SimpleScriptStoreProvider implements EnabledParentStoreProvider, Da FXCollections.observableList(vals), name, selectedExecTypes, v -> false, () -> false); return new OptionsBuilder() - .name("minimumShellDialect") - .description("minimumShellDialectDescription") - .documentationLink(DocumentationLink.SCRIPTING_COMPATIBILITY) - .addComp(choice, dialect) - .name("scriptContents") - .description("scriptContentsDescription") - .documentationLink(DocumentationLink.SCRIPTING_EDITING) - .addComp( - new IntegratedTextAreaComp(commandProp, false, "commands", Bindings.createStringBinding(() -> { - return dialect.getValue() != null - ? dialect.getValue().getScriptFileEnding() - : "sh"; - })), - commandProp) + .nameAndDescription("scriptSourceType") + .sub(textSourceChoice.build(), textSource) + .nonNull() .nameAndDescription("executionType") .documentationLink(DocumentationLink.SCRIPTING_TYPES) .addComp(selectorComp, selectedExecTypes) @@ -178,11 +157,10 @@ public class SimpleScriptStoreProvider implements EnabledParentStoreProvider, Da .bind( () -> { return SimpleScriptStore.builder() + .textSource(textSource.get()) .group(group.get()) - .minimumDialect(dialect.getValue()) .scripts(new ArrayList<>(others.get())) .description(st.getDescription()) - .commands(commandProp.getValue()) .initScript(selectedExecTypes.contains(0)) .runnableScript(selectedExecTypes.contains(1)) .fileScript(selectedExecTypes.contains(2)) diff --git a/ext/base/src/main/java/module-info.java b/ext/base/src/main/java/module-info.java index 6edc0dd46..2a5373569 100644 --- a/ext/base/src/main/java/module-info.java +++ b/ext/base/src/main/java/module-info.java @@ -42,9 +42,7 @@ open module io.xpipe.ext.base { RunBackgroundScriptActionProvider, RunHubBatchScriptActionProvider, RunHubScriptActionProvider, - RunTerminalScriptActionProvider, - ScriptSourceRefreshHubProvider, - ScriptSourceBrowseActionProvider, + RunTerminalScriptActionProvider, ScriptCollectionSourceRefreshHubProvider, ScriptCollectionSourceBrowseActionProvider, SimpleScriptQuickEditHubLeafProvider, StoreStartActionProvider, StoreStopActionProvider, @@ -60,8 +58,7 @@ open module io.xpipe.ext.base { CustomServiceStoreProvider, MappedServiceStoreProvider, FixedServiceStoreProvider, - SimpleScriptStoreProvider, - ScriptSourceStoreProvider, + SimpleScriptStoreProvider, ScriptCollectionSourceStoreProvider, DesktopApplicationStoreProvider, LocalIdentityStoreProvider, SyncedIdentityStoreProvider, diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-16-dark.png b/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-16-dark.png similarity index 100% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-16-dark.png rename to ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-16-dark.png diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-16.png b/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-16.png similarity index 100% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-16.png rename to ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-16.png diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-24-dark.png b/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-24-dark.png similarity index 100% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-24-dark.png rename to ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-24-dark.png diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-24.png b/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-24.png similarity index 100% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-24.png rename to ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-24.png diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-40-dark.png b/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-40-dark.png similarity index 100% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-40-dark.png rename to ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-40-dark.png diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-40.png b/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-40.png similarity index 100% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-40.png rename to ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-40.png diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-80-dark.png b/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-80-dark.png similarity index 100% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-80-dark.png rename to ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-80-dark.png diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-80.png b/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-80.png similarity index 100% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptSource_icon-80.png rename to ext/base/src/main/resources/io/xpipe/ext/base/resources/img/scriptCollectionSource_icon-80.png diff --git a/img/base/scriptSource_icon-dark.svg b/img/base/scriptCollectionSource_icon-dark.svg similarity index 100% rename from img/base/scriptSource_icon-dark.svg rename to img/base/scriptCollectionSource_icon-dark.svg diff --git a/img/base/scriptSource_icon.svg b/img/base/scriptCollectionSource_icon.svg similarity index 100% rename from img/base/scriptSource_icon.svg rename to img/base/scriptCollectionSource_icon.svg diff --git a/lang/strings/translations_en.properties b/lang/strings/translations_en.properties index d6acab829..8e04b1c14 100644 --- a/lang/strings/translations_en.properties +++ b/lang/strings/translations_en.properties @@ -1905,11 +1905,18 @@ scriptDirectory=Directory location scriptDirectoryDescription=The local directory containing shell script files scriptSourceUrl=Repository URL scriptSourceUrlDescription=The URL to a remote git repository containing shell script files -scriptSourceType=Source type -scriptSourceTypeDescription=The type of source from where shell scripts should be loaded +scriptCollectionSourceType=Source type +scriptCollectionSourceTypeDescription=The type of source from where shell scripts should be loaded gitRepository=Git repository -scriptSource.displayName=Script source -scriptSource.displayDescription=Automatically import shell script files from an existing source +scriptCollectionSource.displayName=Script source +scriptCollectionSource.displayDescription=Automatically import shell script files from an existing source directorySource=Directory source gitRepositorySource=Git repository source refreshSource=Refresh source +scriptTextSourceUrl=Script URL +scriptTextSourceUrlDescription=The URL to retrieve the script file from +scriptSourceType=Script source +scriptSourceTypeDescription=From where to source the script +scriptSourceTypeInPlace=In-place +scriptSourceTypeUrl=URL +scriptSourceTypeSource=Source