diff --git a/app/build.gradle b/app/build.gradle index f475d74a..ed3fc133 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -136,7 +136,7 @@ run { systemProperty 'io.xpipe.app.writeLogs', "true" systemProperty 'io.xpipe.app.writeSysOut', "true" systemProperty 'io.xpipe.app.developerMode', "true" - systemProperty 'io.xpipe.app.logLevel', "debug" + systemProperty 'io.xpipe.app.logLevel', "trace" systemProperty 'io.xpipe.app.fullVersion', rootProject.fullVersion // systemProperty "io.xpipe.beacon.port", "21724" // systemProperty "io.xpipe.beacon.printMessages", "true" diff --git a/app/src/main/java/io/xpipe/app/browser/FileBrowserComp.java b/app/src/main/java/io/xpipe/app/browser/FileBrowserComp.java index 1cc14216..767d9ad8 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileBrowserComp.java +++ b/app/src/main/java/io/xpipe/app/browser/FileBrowserComp.java @@ -209,7 +209,7 @@ public class FileBrowserComp extends SimpleComp { ? DataStorage.get() .getStoreEntry(model.getStore().getValue()) .getProvider() - .getDisplayIconFileName() + .getDisplayIconFileName(model.getStore().getValue()) : null; }, model.getStore()); diff --git a/app/src/main/java/io/xpipe/app/browser/FileListComp.java b/app/src/main/java/io/xpipe/app/browser/FileListComp.java index aa77e162..b05be15e 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileListComp.java +++ b/app/src/main/java/io/xpipe/app/browser/FileListComp.java @@ -204,9 +204,9 @@ final class FileListComp extends AnchorPane { } newItems.addAll(newValue); table.getItems().setAll(newItems); - if (newValue.size() > 0) { - table.scrollTo(0); - } +// if (newValue.size() > 0) { +// table.scrollTo(0); +// } }); }); diff --git a/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java b/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java index 45072151..ea2bc111 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java +++ b/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java @@ -4,6 +4,7 @@ import io.xpipe.app.issue.ErrorEvent; import io.xpipe.core.impl.FileNames; import io.xpipe.core.impl.LocalStore; import io.xpipe.core.process.OsType; +import io.xpipe.core.store.ConnectionFileSystem; import io.xpipe.core.store.FileSystem; import java.nio.file.Files; @@ -13,7 +14,25 @@ import java.util.List; public class FileSystemHelper { - public static String normalizeDirectoryPath(OpenFileSystemModel model, String path) { + public static String getStartDirectory(OpenFileSystemModel model) throws Exception { + // Handle special case when file system creation has failed + if (model.getFileSystem() == null) { + return null; + } + + ConnectionFileSystem fileSystem = (ConnectionFileSystem) model.getFileSystem(); + var current = !(model.getStore().getValue() instanceof LocalStore) + ? fileSystem + .getShellControl() + .executeStringSimpleCommand(fileSystem + .getShellControl() + .getShellDialect() + .getPrintWorkingDirectoryCommand()) + : fileSystem.getShell().get().getOsType().getHomeDirectory(fileSystem.getShell().get()); + return FileSystemHelper.normalizeDirectoryPath(model, current); + } + + public static String normalizeDirectoryPath(OpenFileSystemModel model, String path) throws Exception { if (path == null) { return null; } @@ -37,7 +56,11 @@ public class FileSystemHelper { return path + "\\"; } - return FileNames.toDirectory(path); + var normalized = shell.get() + .getShellDialect() + .normalizeDirectory(shell.get(), path) + .readOrThrow(); + return FileNames.toDirectory(normalized); } public static FileSystem.FileEntry getLocal(Path file) throws Exception { diff --git a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java index 1f44c499..57165a92 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java +++ b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java @@ -7,7 +7,6 @@ import io.xpipe.app.util.BusyProperty; import io.xpipe.app.util.TerminalHelper; import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.impl.FileNames; -import io.xpipe.core.impl.LocalStore; import io.xpipe.core.store.ConnectionFileSystem; import io.xpipe.core.store.FileSystem; import io.xpipe.core.store.FileSystemStore; @@ -76,7 +75,14 @@ final class OpenFileSystemModel { } public Optional cd(String path) { - var newPath = FileSystemHelper.normalizeDirectoryPath(this, path); + String newPath = null; + try { + newPath = FileSystemHelper.normalizeDirectoryPath(this, path); + } catch (Exception ex) { + ErrorEvent.fromThrowable(ex).handle(); + return Optional.of(currentPath.get()); + } + if (!Objects.equals(path, newPath)) { return Optional.of(newPath); } @@ -96,7 +102,8 @@ final class OpenFileSystemModel { this.fileSystem = fs; } - path = FileSystemHelper.normalizeDirectoryPath(this, path); + // Assumed that the path is normalized to improve performance! + // path = FileSystemHelper.normalizeDirectoryPath(this, path); navigateToSync(path); filter.setValue(null); @@ -218,14 +225,7 @@ final class OpenFileSystemModel { fs.open(); this.fileSystem = fs; - var current = !(fileSystem instanceof LocalStore) && fs instanceof ConnectionFileSystem connectionFileSystem - ? connectionFileSystem - .getShellControl() - .executeStringSimpleCommand(connectionFileSystem - .getShellControl() - .getShellDialect() - .getPrintWorkingDirectoryCommand()) - : null; + var current = FileSystemHelper.getStartDirectory(this); cdSync(current); } diff --git a/app/src/main/java/io/xpipe/app/comp/source/store/DataStoreSelectorComp.java b/app/src/main/java/io/xpipe/app/comp/source/store/DataStoreSelectorComp.java index af4f27dd..9dc99db3 100644 --- a/app/src/main/java/io/xpipe/app/comp/source/store/DataStoreSelectorComp.java +++ b/app/src/main/java/io/xpipe/app/comp/source/store/DataStoreSelectorComp.java @@ -56,7 +56,7 @@ public class DataStoreSelectorComp extends Comp> { ? DataStoreProviders.byStoreClass(chosenStore.getValue().getClass()) .orElse(null) : null; - var graphic = provider != null ? provider.getDisplayIconFileName() : "file_icon.png"; + var graphic = provider != null ? provider.getDisplayIconFileName(chosenStore.getValue()) : "file_icon.png"; if (chosenStore.getValue() == null || !(chosenStore.getValue() instanceof FileStore f)) { return JfxHelper.createNamedEntry( AppI18n.get("selectStreamStore"), AppI18n.get("openStreamStoreWizard"), graphic); diff --git a/app/src/main/java/io/xpipe/app/comp/source/store/DsStoreProviderChoiceComp.java b/app/src/main/java/io/xpipe/app/comp/source/store/DsStoreProviderChoiceComp.java index 6ac44d45..033f628a 100644 --- a/app/src/main/java/io/xpipe/app/comp/source/store/DsStoreProviderChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/comp/source/store/DsStoreProviderChoiceComp.java @@ -43,7 +43,7 @@ public class DsStoreProviderChoiceComp extends Comp return createDefaultNode(); } - var graphic = provider.getDisplayIconFileName(); + var graphic = provider.getDisplayIconFileName(null); return JfxHelper.createNamedEntry(provider.getDisplayName(), provider.getDisplayDescription(), graphic); } diff --git a/app/src/main/java/io/xpipe/app/comp/source/store/NamedStoreChoiceComp.java b/app/src/main/java/io/xpipe/app/comp/source/store/NamedStoreChoiceComp.java index 1f03672f..0b6c08cc 100644 --- a/app/src/main/java/io/xpipe/app/comp/source/store/NamedStoreChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/comp/source/store/NamedStoreChoiceComp.java @@ -125,7 +125,7 @@ public class NamedStoreChoiceComp extends SimpleComp implements Validatable { var view = new ListViewComp<>(shown, list, prop, (DataStoreEntry e) -> { var provider = e.getProvider(); - var graphic = provider.getDisplayIconFileName(); + var graphic = provider.getDisplayIconFileName(e.getStore()); var top = String.format("%s (%s)", e.getName(), provider.getDisplayName()); var bottom = provider.toSummaryString(e.getStore(), 50); var el = JfxHelper.createNamedEntry(top, bottom, graphic); diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryComp.java index 1a54cdce..28ea1250 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryComp.java @@ -98,7 +98,7 @@ public class StoreEntryComp extends SimpleComp { private Node createIcon() { var img = entry.isDisabled() ? "disabled_icon.png" - : entry.getEntry().getProvider().getDisplayIconFileName(); + : entry.getEntry().getProvider().getDisplayIconFileName(entry.getEntry().getStore()); var imageComp = new PrettyImageComp(new SimpleStringProperty(img), 55, 45); var storeIcon = imageComp.createRegion(); storeIcon.getStyleClass().add("icon"); diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryFlatMiniSection.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryFlatMiniSection.java index 9a2e721d..f7e5a4ca 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryFlatMiniSection.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryFlatMiniSection.java @@ -41,7 +41,9 @@ public class StoreEntryFlatMiniSection extends SimpleComp { @Override protected Region createSimple() { - var image = entry.getState() == DataStoreEntry.State.LOAD_FAILED ? "disabled_icon.png" : entry.getProvider().getDisplayIconFileName(); + var image = entry.getState() == DataStoreEntry.State.LOAD_FAILED + ? "disabled_icon.png" + : entry.getProvider().getDisplayIconFileName(entry.getStore()); var label = new Label(entry.getName(), new PrettyImageComp(new SimpleStringProperty(image), 20, 20).createRegion()); var spacer = new Spacer(depth * 10, Orientation.HORIZONTAL); var box = new HBox(spacer, label); diff --git a/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java b/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java index 08a5b665..f62cbd08 100644 --- a/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java @@ -100,7 +100,7 @@ public interface DataStoreProvider { return i != -1 ? n.substring(i + 1) : n; } - default String getDisplayIconFileName() { + default String getDisplayIconFileName(DataStore store) { return getModuleName() + ":" + getId() + "_icon.png"; } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/FileSystemStoreChoiceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/FileSystemStoreChoiceComp.java index 7a86644a..88c6f95f 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/FileSystemStoreChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/FileSystemStoreChoiceComp.java @@ -34,13 +34,13 @@ public class FileSystemStoreChoiceComp extends SimpleComp { private Region createGraphic(FileSystemStore s) { var provider = DataStoreProviders.byStore(s); - var img = new PrettyImageComp(new SimpleStringProperty(provider.getDisplayIconFileName()), 16, 16); + var img = new PrettyImageComp(new SimpleStringProperty(provider.getDisplayIconFileName(s)), 16, 16); return new Label(getName(s), img.createRegion()); } private Region createDisplayGraphic(FileSystemStore s) { var provider = DataStoreProviders.byStore(s); - var img = new PrettyImageComp(new SimpleStringProperty(provider.getDisplayIconFileName()), 16, 16); + var img = new PrettyImageComp(new SimpleStringProperty(provider.getDisplayIconFileName(s)), 16, 16); return new Label(null, img.createRegion()); } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/ShellStoreChoiceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/ShellStoreChoiceComp.java index d2934630..e5ad6380 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/ShellStoreChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/ShellStoreChoiceComp.java @@ -54,7 +54,7 @@ public class ShellStoreChoiceComp extends SimpleComp { protected Region createGraphic(T s) { var provider = DataStoreProviders.byStore(s); var imgView = - new PrettyImageComp(new SimpleStringProperty(provider.getDisplayIconFileName()), 16, 16).createRegion(); + new PrettyImageComp(new SimpleStringProperty(provider.getDisplayIconFileName(s)), 16, 16).createRegion(); var name = DataStorage.get().getUsableStores().stream() .filter(e -> e.equals(s)) diff --git a/core/src/main/java/io/xpipe/core/charsetter/StreamCharset.java b/core/src/main/java/io/xpipe/core/charsetter/StreamCharset.java index 26d43e00..828b9013 100644 --- a/core/src/main/java/io/xpipe/core/charsetter/StreamCharset.java +++ b/core/src/main/java/io/xpipe/core/charsetter/StreamCharset.java @@ -3,6 +3,9 @@ package io.xpipe.core.charsetter; import io.xpipe.core.util.Identifiers; import lombok.Value; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -117,6 +120,17 @@ public class StreamCharset { byte[] byteOrderMark; List names; + public Reader reader(InputStream stream) throws Exception { + if (hasByteOrderMark()) { + var bom = stream.readNBytes(getByteOrderMark().length); + if (bom.length != 0 && !Arrays.equals(bom, getByteOrderMark())) { + throw new IllegalStateException("Charset does not match: " + charset.toString()); + } + } + + return new InputStreamReader(stream, charset); + } + public static StreamCharset get(Charset charset, boolean byteOrderMark) { return ALL.stream() .filter(streamCharset -> diff --git a/core/src/main/java/io/xpipe/core/process/ProcessControl.java b/core/src/main/java/io/xpipe/core/process/ProcessControl.java index ec23cd66..4fa3ad73 100644 --- a/core/src/main/java/io/xpipe/core/process/ProcessControl.java +++ b/core/src/main/java/io/xpipe/core/process/ProcessControl.java @@ -9,6 +9,8 @@ import java.util.concurrent.ExecutorService; public interface ProcessControl extends Closeable, AutoCloseable { + void resetData(); + ExecutorService getStdoutReader(); ExecutorService getStderrReader(); diff --git a/core/src/main/java/io/xpipe/core/process/ShellDialect.java b/core/src/main/java/io/xpipe/core/process/ShellDialect.java index d055ffaa..5bca7da1 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellDialect.java +++ b/core/src/main/java/io/xpipe/core/process/ShellDialect.java @@ -2,6 +2,7 @@ package io.xpipe.core.process; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.xpipe.core.charsetter.NewLine; +import io.xpipe.core.charsetter.StreamCharset; import io.xpipe.core.store.FileSystem; import java.nio.charset.Charset; @@ -13,6 +14,12 @@ import java.util.stream.Stream; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") public interface ShellDialect { + default StreamCharset getTextFileCharset(ShellControl sc) { + return StreamCharset.get(sc.getCharset(), false); + } + + CommandControl normalizeDirectory(ShellControl shellControl, String directory); + String fileArgument(String s); default String applyRcFileCommand() { @@ -91,6 +98,10 @@ public interface ShellDialect { String prepareInitFileOpenCommand(ShellControl parent, String file); + String runScript(String file); + + String sourceScript(String file); + String executeCommandWithShell(String cmd); String getMkdirsCommand(String dirs); diff --git a/ext/base/src/main/java/io/xpipe/ext/base/LocalStoreProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/LocalStoreProvider.java deleted file mode 100644 index 3dc4a861..00000000 --- a/ext/base/src/main/java/io/xpipe/ext/base/LocalStoreProvider.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.xpipe.ext.base; - -import io.xpipe.app.ext.DataStoreProvider; -import io.xpipe.app.storage.DataStorage; -import io.xpipe.app.storage.DataStoreEntry; -import io.xpipe.app.storage.StorageElement; -import io.xpipe.core.impl.LocalStore; -import io.xpipe.core.process.OsType; -import io.xpipe.core.store.DataStore; - -import java.util.List; -import java.util.UUID; - -public class LocalStoreProvider implements DataStoreProvider { - - @Override - public String queryInformationString(DataStore store, int length) throws Exception { - try (var pc = LocalStore.getShell().start()) { - return OsType.getLocal().determineOperatingSystemName(pc); - } - } - - @Override - public String toSummaryString(DataStore store, int length) { - return "localhost"; - } - - @Override - public boolean shouldShow() { - return false; - } - - @Override - public void storageInit() throws Exception { - var hasLocal = DataStorage.get().getUsableStores().stream() - .anyMatch(dataStore -> dataStore instanceof LocalStore); - if (hasLocal) { - return; - } - - var e = DataStoreEntry.createNew(UUID.randomUUID(), "Local Machine", new LocalStore()); - DataStorage.get().addStoreEntry(e); - e.setConfiguration(StorageElement.Configuration.builder() - .deletable(false) - .editable(false) - .refreshable(true) - .renameable(false) - .build()); - e.refresh(true); - } - - @Override - public DataStore defaultStore() { - return new LocalStore(); - } - - @Override - public String getDisplayName() { - return null; - } - - @Override - public List getPossibleNames() { - return List.of("local", "localhost"); - } - - @Override - public List> getStoreClasses() { - return List.of(LocalStore.class); - } -} diff --git a/ext/base/src/main/java/module-info.java b/ext/base/src/main/java/module-info.java index e93d2492..0cd23a0f 100644 --- a/ext/base/src/main/java/module-info.java +++ b/ext/base/src/main/java/module-info.java @@ -44,7 +44,6 @@ open module io.xpipe.ext.base { provides DataStoreProvider with SinkDrainStoreProvider, HttpStoreProvider, - LocalStoreProvider, InternalStreamProvider, FileStoreProvider, InMemoryStoreProvider; diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/cmd.png b/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/cmd.png deleted file mode 100644 index cc7a2bd8..00000000 Binary files a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/cmd.png and /dev/null differ diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/local_icon.png b/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/local_icon.png deleted file mode 100644 index 6682cd80..00000000 Binary files a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/local_icon.png and /dev/null differ diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/powershell.png b/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/powershell.png deleted file mode 100644 index e7d50811..00000000 Binary files a/ext/base/src/main/resources/io/xpipe/ext/base/resources/img/powershell.png and /dev/null differ