Merge branch no-stderr into master

This commit is contained in:
crschnick 2024-08-09 07:38:47 +00:00
parent 65b2be5709
commit 9860b0c10f
34 changed files with 305 additions and 200 deletions

View file

@ -33,25 +33,48 @@ public class SystemStateComp extends SimpleComp {
PlatformThread.runLaterIfNeeded(() -> fi.setIconLiteral(i));
});
var border = new FontIcon("mdi2c-circle-outline");
var bg = new FontIcon("mdi2s-square-rounded");
bg.getStyleClass().add("background-icon");
var border = new FontIcon("mdi2s-square-rounded-outline");
border.getStyleClass().add("outer-icon");
border.setOpacity(0.5);
border.setOpacity(0.3);
var success = Styles.toDataURI(
".stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-success-emphasis; }");
"""
.stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-success-emphasis; }
.stacked-ikonli-font-icon > .background-icon { -fx-icon-color: -color-success-9; }
"""
);
var failure =
Styles.toDataURI(".stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-danger-emphasis; }");
Styles.toDataURI(
"""
.stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-danger-emphasis; }
.stacked-ikonli-font-icon > .background-icon { -fx-icon-color: -color-danger-9; }
"""
);
var other =
Styles.toDataURI(".stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-accent-emphasis; }");
Styles.toDataURI(
"""
.stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-accent-emphasis; }
.stacked-ikonli-font-icon > .background-icon { -fx-icon-color: -color-accent-9; }
"""
);
var pane = new StackedFontIcon();
pane.getChildren().addAll(fi, border);
pane.getChildren().addAll(bg, fi, border);
pane.setAlignment(Pos.CENTER);
var dataClass1 =
"""
.stacked-ikonli-font-icon > .outer-icon {
-fx-icon-size: 22px;
-fx-icon-size: 26px;
}
.stacked-ikonli-font-icon > .background-icon {
-fx-icon-size: 26px;
}
.stacked-ikonli-font-icon > .inner-icon {
-fx-icon-size: 12px;

View file

@ -0,0 +1,50 @@
package io.xpipe.app.comp.base;
import atlantafx.base.theme.Styles;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.TooltipAugment;
import javafx.geometry.Pos;
import javafx.scene.layout.Region;
import lombok.Getter;
import org.kordamp.ikonli.javafx.FontIcon;
import org.kordamp.ikonli.javafx.StackedFontIcon;
@Getter
public class TtyWarningComp extends SimpleComp {
@Override
protected Region createSimple() {
var fi = new FontIcon("mdi2l-lightning-bolt");
fi.getStyleClass().add("inner-icon");
var border = new FontIcon("mdi2s-square-rounded-outline");
border.getStyleClass().add("outer-icon");
border.setOpacity(0.5);
var bg = new FontIcon("mdi2s-square-rounded");
bg.getStyleClass().add("background-icon");
var pane = new StackedFontIcon();
pane.getChildren().addAll(bg, fi, border);
pane.setAlignment(Pos.CENTER);
var style =
"""
.stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-danger-emphasis; }
.stacked-ikonli-font-icon > .outer-icon {
-fx-icon-size: 26px;
}
.stacked-ikonli-font-icon > .background-icon {
-fx-icon-size: 26px;
-fx-icon-color: -color-danger-9;
}
.stacked-ikonli-font-icon > .inner-icon {
-fx-icon-size: 12px;
}
""";
pane.getStylesheets().add(Styles.toDataURI(style));
new TooltipAugment<>("ttyWarning", null).augment(pane);
return pane;
}
}

View file

@ -10,6 +10,7 @@ import javafx.beans.value.ObservableValue;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCombination;
import javafx.stage.Window;
import javafx.util.Duration;
public class TooltipAugment<S extends CompStructure<?>> implements Augment<S> {
@ -45,6 +46,7 @@ public class TooltipAugment<S extends CompStructure<?>> implements Augment<S> {
tt.setWrapText(true);
tt.setMaxWidth(400);
tt.getStyleClass().add("fancy-tooltip");
tt.setHideDelay(Duration.INDEFINITE);
Tooltip.install(struc.get(), tt);
}

View file

@ -109,6 +109,9 @@ public class AppPrefs {
map(new SimpleBooleanProperty(false), "developerDisableGuiRestrictions", Boolean.class);
private final ObservableBooleanValue developerDisableGuiRestrictionsEffective =
bindDeveloperTrue(developerDisableGuiRestrictions);
final BooleanProperty developerForceSshTty =
map(new SimpleBooleanProperty(false), "developerForceSshTty", Boolean.class);
final ObjectProperty<SupportedLocale> language =
map(new SimpleObjectProperty<>(SupportedLocale.getEnglish()), "language", SupportedLocale.class);
@ -435,6 +438,10 @@ public class AppPrefs {
return developerDisableGuiRestrictionsEffective;
}
public ObservableBooleanValue developerForceSshTty() {
return bindDeveloperTrue(developerForceSshTty);
}
@SuppressWarnings("unchecked")
private <T> T map(T o, String name, Class<?> clazz) {
mapping.add(new Mapping<>(name, (Property<T>) o, (Class<T>) clazz));

View file

@ -61,6 +61,8 @@ public class DeveloperCategory extends AppPrefsCategory {
.sub(new OptionsBuilder()
.nameAndDescription("developerDisableUpdateVersionCheck")
.addToggle(prefs.developerDisableUpdateVersionCheck)
.nameAndDescription("developerForceSshTty")
.addToggle(prefs.developerForceSshTty)
.nameAndDescription("developerDisableGuiRestrictions")
.addToggle(prefs.developerDisableGuiRestrictions)
.nameAndDescription("shellCommandTest")

View file

@ -114,14 +114,12 @@ public abstract class ExternalApplicationType implements PrefsChoiceValue {
protected Optional<Path> determineFromPath() {
// Try to locate if it is in the Path
try (var cc = LocalShell.getShell()
.command(CommandBuilder.ofFunction(
var1 -> var1.getShellDialect().getWhichCommand(executable)))
try (var sc = LocalShell.getShell()
.start()) {
var out = cc.readStdoutDiscardErr();
var exit = cc.getExitCode();
if (exit == 0) {
var first = out.lines().findFirst();
var out = sc.command(CommandBuilder.ofFunction(
var1 -> var1.getShellDialect().getWhichCommand(executable))).readStdoutIfPossible();
if (out.isPresent()) {
var first = out.get().lines().findFirst();
if (first.isPresent()) {
return first.map(String::trim).map(Path::of);
}

View file

@ -99,11 +99,9 @@ public enum XPipeDistributionType {
// In theory, we can also add && !AppProperties.get().isStaging() here, but we want to replicate the
// production behavior
if (OsType.getLocal().equals(OsType.WINDOWS)) {
try (var chocoOut =
sc.command("choco search --local-only -r xpipe").start()) {
var out = chocoOut.readStdoutDiscardErr();
if (chocoOut.getExitCode() == 0) {
var split = out.split("\\|");
var out = sc.command("choco search --local-only -r xpipe").readStdoutIfPossible();
if (out.isPresent()) {
var split = out.get().split("\\|");
if (split.length == 2) {
var version = split[1];
if (AppProperties.get().getVersion().equals(version)) {
@ -112,15 +110,13 @@ public enum XPipeDistributionType {
}
}
}
}
// In theory, we can also add && !AppProperties.get().isStaging() here, but we want to replicate the
// production behavior
if (OsType.getLocal().equals(OsType.MACOS)) {
try (var brewOut = sc.command("brew list --casks --versions").start()) {
var out = brewOut.readStdoutDiscardErr();
if (brewOut.getExitCode() == 0) {
if (out.lines().anyMatch(s -> {
var out = sc.command("brew list --casks --versions").readStdoutIfPossible();
if (out.isPresent()) {
if (out.get().lines().anyMatch(s -> {
var split = s.split(" ");
return split.length == 2
&& split[0].equals("xpipe")
@ -130,7 +126,6 @@ public enum XPipeDistributionType {
}
}
}
}
} catch (Exception ex) {
ErrorEvent.fromThrowable(ex).handle();
}

View file

@ -16,11 +16,10 @@ public class DesktopHelper {
return Path.of(LocalShell.getLocalPowershell()
.executeSimpleStringCommand("[Environment]::GetFolderPath([Environment+SpecialFolder]::Desktop)"));
} else if (OsType.getLocal() == OsType.LINUX) {
try (var cmd = LocalShell.getShell().command("xdg-user-dir DESKTOP").start()) {
var read = cmd.readStdoutDiscardErr();
var exit = cmd.getExitCode();
if (exit == 0) {
return Path.of(read);
try (var sc = LocalShell.getShell().start()) {
var out = sc.command("xdg-user-dir DESKTOP").readStdoutIfPossible();
if (out.isPresent()) {
return Path.of(out.get());
}
}
}
@ -34,12 +33,10 @@ public class DesktopHelper {
.executeSimpleStringCommand(
"(New-Object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.Path"));
} else if (OsType.getLocal() == OsType.LINUX) {
try (var cmd =
LocalShell.getShell().command("xdg-user-dir DOWNLOAD").start()) {
var read = cmd.readStdoutDiscardErr();
var exit = cmd.getExitCode();
if (exit == 0) {
return Path.of(read);
try (var sc = LocalShell.getShell().start()) {
var out = sc.command("xdg-user-dir DOWNLOAD").readStdoutIfPossible();
if (out.isPresent()) {
return Path.of(out.get());
}
}
}

View file

@ -145,23 +145,20 @@ public abstract class WindowsRegistry {
.add("/v")
.addQuoted(valueName);
String output;
try (var c = shellControl.command(command).start()) {
output = c.readStdoutDiscardErr();
if (c.getExitCode() != 0) {
var output = shellControl.command(command).readStdoutIfPossible();
if (output.isEmpty()) {
return Optional.empty();
}
}
// Output has the following format:
// \n<Version information>\n\n<key>\t<registry type>\t<value>
if (output.contains("\t")) {
String[] parsed = output.split("\t");
if (output.get().contains("\t")) {
String[] parsed = output.get().split("\t");
return Optional.of(parsed[parsed.length - 1]);
}
if (output.contains(" ")) {
String[] parsed = output.split(" ");
if (output.get().contains(" ")) {
String[] parsed = output.get().split(" ");
return Optional.of(parsed[parsed.length - 1]);
}
@ -176,14 +173,7 @@ public abstract class WindowsRegistry {
.add("/v")
.addQuoted(valueName)
.add("/s");
try (var c = shellControl.command(command).start()) {
var output = c.readStdoutDiscardErr();
if (c.getExitCode() != 0) {
return Optional.empty();
} else {
return Optional.of(output);
}
}
return shellControl.command(command).readStdoutIfPossible();
}
@Override
@ -196,11 +186,7 @@ public abstract class WindowsRegistry {
.add("/s")
.add("/e")
.add("/d");
try (var c = shellControl.command(command).start()) {
var output = c.readStdoutDiscardErr();
if (c.getExitCode() != 0) {
return Optional.empty();
} else {
return shellControl.command(command).readStdoutIfPossible().flatMap(output -> {
return output.lines().findFirst().flatMap(s -> {
if (s.startsWith("HKEY_CURRENT_USER\\")) {
return Optional.of(new Key(HKEY_CURRENT_USER, s.replace("HKEY_CURRENT_USER\\", "")));
@ -210,8 +196,7 @@ public abstract class WindowsRegistry {
}
return Optional.empty();
});
}
}
});
}
}
}

View file

@ -1,11 +1,10 @@
## Welcome
Thank you for using XPipe!
Welcome to XPipe!
You can view the development status, report issues, and more at the following places:
- [GitHub Repository](https://github.com/xpipe-io/xpipe/)
- [Discord Server](https://discord.gg/8y89vS8cRb)
- [Slack Server](https://join.slack.com/t/XPipe/shared_invite/zt-1awjq0t5j-5i4UjNJfNe1VN4b_auu6Cg)
- [Email me](mailto://crschnick@xpipe.io)
Note that the XPipe project currently is a one-man show, but I still try to respond to everything in time.
- [Email us](mailto://hello@xpipe.io)

View file

@ -128,3 +128,7 @@
.root:dark .loading-comp {
-fx-background-color: rgba(0, 0, 0, 0.5);
}
.root:light .stacked-ikonli-font-icon > .background-icon { -fx-opacity: 0; }
.stacked-ikonli-font-icon > .background-icon { -fx-opacity: 0.2; }

View file

@ -1,16 +1,10 @@
package io.xpipe.core.process;
import io.xpipe.core.util.FailableConsumer;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.time.Duration;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
public interface CommandControl extends ProcessControl {
@ -70,32 +64,14 @@ public interface CommandControl extends ProcessControl {
CommandControl elevated(ElevationFunction function);
void withStdoutOrThrow(FailableConsumer<InputStreamReader, Exception> c);
String[] readStdoutAndStderr() throws Exception;
String readStdoutDiscardErr() throws Exception;
String readStderrDiscardStdout() throws Exception;
void discardOrThrow() throws Exception;
void accumulateStdout(Consumer<String> con);
void accumulateStderr(Consumer<String> con);
byte[] readRawBytesOrThrow() throws Exception;
String readStdoutOrThrow() throws Exception;
JsonNode readStdoutJsonOrThrow() throws Exception;
String readStderrOrThrow() throws Exception;
String readStdoutAndWait() throws Exception;
String readStderrAndWait() throws Exception;
Optional<String> readStdoutIfPossible() throws Exception;
default boolean discardAndCheckExit() throws ProcessOutputException {
@ -113,10 +89,6 @@ public interface CommandControl extends ProcessControl {
}
}
void discardOut();
void discardErr();
enum TerminalExitMode {
KEEP_OPEN,
CLOSE

View file

@ -1,6 +0,0 @@
package io.xpipe.core.process;
public interface CommandFeedbackPredicate {
boolean test(CommandBuilder command);
}

View file

@ -181,19 +181,15 @@ public interface OsType {
@Override
public String determineOperatingSystemName(ShellControl pc) throws Exception {
String type = "Unknown";
try (CommandControl c = pc.command("uname -o").start()) {
var text = c.readStdoutDiscardErr();
if (c.getExitCode() == 0) {
type = text.strip();
}
var uname = pc.command("uname -o").readStdoutIfPossible();
if (uname.isPresent()) {
type = uname.get();
}
String version = "?";
try (CommandControl c = pc.command("uname -r").start()) {
var text = c.readStdoutDiscardErr();
if (c.getExitCode() == 0) {
version = text.strip();
}
var unameR = pc.command("uname -r").readStdoutIfPossible();
if (unameR.isPresent()) {
version = unameR.get();
}
return type + " " + version;
@ -209,18 +205,14 @@ public interface OsType {
@Override
public String determineOperatingSystemName(ShellControl pc) throws Exception {
try (CommandControl c = pc.command("lsb_release -a").start()) {
var text = c.readStdoutDiscardErr();
if (c.getExitCode() == 0) {
return PropertiesFormatsParser.parse(text, ":").getOrDefault("Description", "Unknown");
}
var rel = pc.command("lsb_release -a").readStdoutIfPossible();
if (rel.isPresent()) {
return PropertiesFormatsParser.parse(rel.get(), ":").getOrDefault("Description", "Unknown");
}
try (CommandControl c = pc.command("cat /etc/*release").start()) {
var text = c.readStdoutDiscardErr();
if (c.getExitCode() == 0) {
return PropertiesFormatsParser.parse(text, "=").getOrDefault("PRETTY_NAME", "Unknown");
}
var cat = pc.command("cat /etc/*release").readStdoutIfPossible();
if (cat.isPresent()) {
return PropertiesFormatsParser.parse(cat.get(), "=").getOrDefault("PRETTY_NAME", "Unknown");
}
return super.determineOperatingSystemName(pc);

View file

@ -18,6 +18,8 @@ import java.util.function.Function;
public interface ShellControl extends ProcessControl {
ShellTtyState getTtyState();
void setNonInteractive();
boolean isInteractive();
@ -65,6 +67,7 @@ public interface ShellControl extends ProcessControl {
var s = store.getState().toBuilder()
.osType(shellControl.getOsType())
.shellDialect(shellControl.getOriginalShellDialect())
.ttyState(shellControl.getTtyState())
.running(true)
.osName(shellControl.getOsName())
.build();
@ -113,25 +116,12 @@ public interface ShellControl extends ProcessControl {
script));
}
default byte[] executeSimpleRawBytesCommand(String command) throws Exception {
try (CommandControl c = command(command).start()) {
return c.readRawBytesOrThrow();
}
}
default String executeSimpleStringCommand(String command) throws Exception {
try (CommandControl c = command(command).start()) {
return c.readStdoutOrThrow();
}
}
default Optional<String> executeSimpleStringCommandAndCheck(String command) throws Exception {
try (CommandControl c = command(command).start()) {
var out = c.readStdoutDiscardErr();
return c.getExitCode() == 0 ? Optional.of(out) : Optional.empty();
}
}
default boolean executeSimpleBooleanCommand(String command) throws Exception {
try (CommandControl c = command(command).start()) {
return c.discardAndCheckExit();
@ -150,20 +140,6 @@ public interface ShellControl extends ProcessControl {
}
}
default void executeSimpleCommand(String command, String failMessage) throws Exception {
try (CommandControl c = command(command).start()) {
c.discardOrThrow();
} catch (ProcessOutputException out) {
throw ProcessOutputException.withPrefix(failMessage, out);
}
}
default String executeSimpleStringCommand(ShellDialect type, String command) throws Exception {
try (var sub = subShell(type).start()) {
return sub.executeSimpleStringCommand(command);
}
}
ShellControl withSecurityPolicy(ShellSecurityPolicy policy);
ShellSecurityPolicy getEffectiveSecurityPolicy();

View file

@ -184,5 +184,5 @@ public interface ShellDialect {
String getDisplayName();
boolean doesEchoInput();
boolean doesEchoInputByDefault();
}

View file

@ -1,10 +0,0 @@
package io.xpipe.core.process;
import lombok.Value;
@Value
public class ShellProperties {
ShellDialect dialect;
boolean ansiEscapes;
}

View file

@ -19,6 +19,7 @@ public class ShellStoreState extends DataStoreState implements OsNameState {
OsType.Any osType;
String osName;
ShellDialect shellDialect;
ShellTtyState ttyState;
Boolean running;
public boolean isRunning() {
@ -39,6 +40,7 @@ public class ShellStoreState extends DataStoreState implements OsNameState {
b.osType(useNewer(osType, shellStoreState.getOsType()))
.osName(useNewer(osName, shellStoreState.getOsName()))
.shellDialect(useNewer(shellDialect, shellStoreState.getShellDialect()))
.ttyState(useNewer(ttyState, shellStoreState.getTtyState()))
.running(useNewer(running, shellStoreState.getRunning()));
}
}

View file

@ -0,0 +1,25 @@
package io.xpipe.core.process;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
@Getter
public enum ShellTtyState {
@JsonProperty("none")
NONE(true, false, false),
@JsonProperty("merged")
MERGED_STDERR(false, false, false),
@JsonProperty("pty")
PTY_ALLOCATED(false, true, true);
private final boolean hasSeparateStreams;
private final boolean hasAnsiEscapes;
private final boolean echoesAllInput;
ShellTtyState(boolean hasSeparateStreams, boolean hasAnsiEscapes, boolean echoesAllInput) {
this.hasSeparateStreams = hasSeparateStreams;
this.hasAnsiEscapes = hasAnsiEscapes;
this.echoesAllInput = echoesAllInput;
}
}

View file

@ -10,13 +10,11 @@ import io.xpipe.core.process.ShellControl;
import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.store.LocalStore;
import io.xpipe.core.store.ShellStore;
import javafx.beans.value.ObservableValue;
import lombok.Value;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StringReader;
public class SampleStoreAction implements ActionProvider {
@ -83,24 +81,15 @@ public class SampleStoreAction implements ActionProvider {
sc.executeSimpleStringCommand(sc.getShellDialect().getEchoCommand("hello!", false));
// You can also implement custom handling for more complex commands
try (CommandControl cc = sc.command("ls").start()) {
// Discard stderr
cc.discardErr();
var lsOut = sc.command("ls").readStdoutOrThrow();
// Read the stdout lines as a stream
BufferedReader reader = new BufferedReader(new InputStreamReader(cc.getStdout(), cc.getCharset()));
BufferedReader reader = new BufferedReader(new StringReader(lsOut));
// We don't have to close this stream here, that will be automatically done by the command control
// after the try-with block
reader.lines().filter(s -> !s.isBlank()).forEach(s -> {
System.out.println(s);
});
// Waits for command completion and returns exit code
if (cc.getExitCode() != 0) {
// Handle failure
}
}
// Commands can also be more complex and span multiple lines.
// In this case, XPipe will internally write a command to a script file and then execute the script
try (CommandControl cc = sc.command(

View file

@ -16,12 +16,10 @@ public abstract class ToFileCommandAction implements LeafAction, ApplicationPath
ShellControl sc = model.getFileSystem().getShell().orElseThrow();
for (BrowserEntry entry : entries) {
var command = createCommand(model, entry);
try (var cc = sc.command(command)
var out = sc.command(command)
.withWorkingDirectory(model.getCurrentDirectory().getPath())
.start()) {
cc.discardErr();
FileOpener.openCommandOutput(entry.getFileName(), entry, cc);
}
.readStdoutOrThrow();
FileOpener.openReadOnlyString(out);
}
}

View file

@ -0,0 +1,69 @@
package io.xpipe.ext.base.store;
import io.xpipe.app.browser.session.BrowserSessionModel;
import io.xpipe.app.comp.base.OsLogoComp;
import io.xpipe.app.comp.base.SystemStateComp;
import io.xpipe.app.comp.base.TtyWarningComp;
import io.xpipe.app.comp.store.StoreEntryComp;
import io.xpipe.app.comp.store.StoreEntryWrapper;
import io.xpipe.app.comp.store.StoreSection;
import io.xpipe.app.ext.ActionProvider;
import io.xpipe.app.ext.DataStoreProvider;
import io.xpipe.app.ext.DataStoreUsageCategory;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.util.TerminalLauncher;
import io.xpipe.core.process.ShellStoreState;
import io.xpipe.core.process.ShellTtyState;
import io.xpipe.core.store.ShellStore;
import io.xpipe.ext.base.script.ScriptStore;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
public interface ShellStoreProvider extends DataStoreProvider {
default Comp<?> createTtyWarning(StoreEntryWrapper w) {
return new TtyWarningComp().hide(Bindings.createObjectBinding(
() -> {
ShellStoreState state = (ShellStoreState) w.getPersistentState().getValue();
return state.getTtyState() == ShellTtyState.NONE;
},
w.getPersistentState()));
}
@Override
default StoreEntryComp customEntryComp(StoreSection s, boolean preferLarge) {
return StoreEntryComp.create(s, createTtyWarning(s.getWrapper()), preferLarge);
}
@Override
default ActionProvider.Action launchAction(DataStoreEntry entry) {
return new ActionProvider.Action() {
@Override
public void execute() throws Exception {
ShellStore store = entry.getStore().asNeeded();
TerminalLauncher.open(entry, DataStorage.get().getStoreEntryDisplayName(entry), null, ScriptStore.controlWithDefaultScripts(store.control()));
}
};
}
@Override
default ActionProvider.Action browserAction(BrowserSessionModel sessionModel, DataStoreEntry store, BooleanProperty busy) {
return new ActionProvider.Action() {
@Override
public void execute() throws Exception {
sessionModel.openFileSystemAsync(store.ref(), null, busy);
}
};
}
default Comp<?> stateDisplay(StoreEntryWrapper w) {
return new OsLogoComp(w, SystemStateComp.State.shellState(w));
}
@Override
default DataStoreUsageCategory getUsageCategory() {
return DataStoreUsageCategory.SHELL;
}
}

View file

@ -500,3 +500,6 @@ workspaceNameDescription=Visningsnavnet på arbejdsområdet
workspacePath=Sti til arbejdsområde
workspacePathDescription=Placeringen af arbejdsområdets datakatalog
workspaceCreationAlertTitle=Oprettelse af arbejdsområde
developerForceSshTty=Fremtving SSH TTY
developerForceSshTtyDescription=Få alle SSH-forbindelser til at tildele en pty for at teste understøttelsen af en manglende stderr og en pty.
ttyWarning=Forbindelsen har tvangstildelt en pty/tty og giver ikke en separat stderr-strøm.\n\nDet kan føre til et par problemer.\n\nHvis du kan, så prøv at få forbindelseskommandoen til ikke at tildele en pty.

View file

@ -494,3 +494,6 @@ workspaceNameDescription=Der Anzeigename des Arbeitsbereichs
workspacePath=Pfad zum Arbeitsbereich
workspacePathDescription=Der Ort des Datenverzeichnisses des Arbeitsbereichs
workspaceCreationAlertTitle=Arbeitsbereich erstellen
developerForceSshTty=SSH TTY erzwingen
developerForceSshTtyDescription=Lass alle SSH-Verbindungen ein pty zuweisen, um die Unterstützung für einen fehlenden stderr und ein pty zu testen.
ttyWarning=Die Verbindung hat zwangsweise ein pty/tty zugewiesen und stellt keinen separaten stderr-Stream zur Verfügung.\n\nDas kann zu einigen Problemen führen.\n\nWenn du kannst, solltest du dafür sorgen, dass der Verbindungsbefehl kein pty zuweist.

View file

@ -498,3 +498,6 @@ workspaceNameDescription=The display name of the workspace
workspacePath=Workspace path
workspacePathDescription=The location of the workspace data directory
workspaceCreationAlertTitle=Workspace creation
developerForceSshTty=Force SSH TTY
developerForceSshTtyDescription=Make all SSH connections allocate a pty to test the support for a missing stderr and a pty.
ttyWarning=The connection has forcefully allocated a pty/tty and does not provide a separate stderr stream.\n\nThis might lead to a few problems.\n\nIf you can, look into making the connection command not allocate a pty.

View file

@ -481,3 +481,6 @@ workspaceNameDescription=El nombre para mostrar del espacio de trabajo
workspacePath=Ruta del espacio de trabajo
workspacePathDescription=La ubicación del directorio de datos del espacio de trabajo
workspaceCreationAlertTitle=Creación de espacios de trabajo
developerForceSshTty=Forzar SSH TTY
developerForceSshTtyDescription=Haz que todas las conexiones SSH asignen una pty para probar la compatibilidad con una stderr y una pty ausentes.
ttyWarning=La conexión ha asignado forzosamente un pty/tty y no proporciona un flujo stderr separado.\n\nEsto puede provocar algunos problemas.\n\nSi puedes, intenta que el comando de conexión no asigne una pty.

View file

@ -481,3 +481,6 @@ workspaceNameDescription=Le nom d'affichage de l'espace de travail
workspacePath=Chemin d'accès à l'espace de travail
workspacePathDescription=L'emplacement du répertoire de données de l'espace de travail
workspaceCreationAlertTitle=Création d'un espace de travail
developerForceSshTty=Force SSH TTY
developerForceSshTtyDescription=Fais en sorte que toutes les connexions SSH allouent un pty pour tester la prise en charge d'un stderr et d'un pty manquants.
ttyWarning=La connexion a alloué de force un pty/tty et ne fournit pas de flux stderr séparé.\n\nCela peut entraîner quelques problèmes.\n\nSi tu le peux, essaie de faire en sorte que la commande de connexion n'alloue pas de pty.

View file

@ -481,3 +481,6 @@ workspaceNameDescription=Il nome di visualizzazione dell'area di lavoro
workspacePath=Percorso dello spazio di lavoro
workspacePathDescription=La posizione della directory dei dati dell'area di lavoro
workspaceCreationAlertTitle=Creazione di uno spazio di lavoro
developerForceSshTty=Forza SSH TTY
developerForceSshTtyDescription=Fai in modo che tutte le connessioni SSH allocino una pty per testare il supporto di una stderr e di una pty mancanti.
ttyWarning=La connessione ha allocato forzatamente una pty/tty e non fornisce un flusso stderr separato.\n\nQuesto potrebbe causare alcuni problemi.\n\nSe puoi, cerca di fare in modo che il comando di connessione non allarghi una pty.

View file

@ -481,3 +481,6 @@ workspaceNameDescription=ワークスペースの表示名
workspacePath=ワークスペースのパス
workspacePathDescription=ワークスペースのデータディレクトリの場所
workspaceCreationAlertTitle=ワークスペースの作成
developerForceSshTty=強制SSH TTY
developerForceSshTtyDescription=すべてのSSHコネクションにptyを割り当て、stderrとptyがない場合のサポートをテストする。
ttyWarning=接続が強制的にpty/ttyを割り当て、個別のstderrストリームを提供しない。\n\nこれはいくつかの問題を引き起こす可能性がある。\n\n可能であれば、接続コマンドで pty を割り当てないようにすることを検討してほしい。

View file

@ -481,3 +481,6 @@ workspaceNameDescription=De weergavenaam van de werkruimte
workspacePath=Werkruimte pad
workspacePathDescription=De locatie van de gegevensmap van de werkruimte
workspaceCreationAlertTitle=Werkruimte maken
developerForceSshTty=SSH TTY afdwingen
developerForceSshTtyDescription=Laat alle SSH-verbindingen een pty toewijzen om de ondersteuning voor een ontbrekende stderr en een pty te testen.
ttyWarning=De verbinding heeft geforceerd een pty/tty toegewezen en biedt geen aparte stderr stream.\n\nDit kan tot een paar problemen leiden.\n\nAls je kunt, kijk dan of je het connection commando geen pty kunt laten toewijzen.

View file

@ -481,3 +481,6 @@ workspaceNameDescription=O nome de apresentação do espaço de trabalho
workspacePath=Caminho do espaço de trabalho
workspacePathDescription=A localização do diretório de dados do espaço de trabalho
workspaceCreationAlertTitle=Criação de espaço de trabalho
developerForceSshTty=Força o SSH TTY
developerForceSshTtyDescription=Faz com que todas as ligações SSH atribuam um pty para testar o suporte para um stderr e um pty em falta.
ttyWarning=A ligação atribuiu à força um pty/tty e não fornece um fluxo stderr separado.\n\nIsto pode levar a alguns problemas.\n\nSe puderes, tenta fazer com que o comando de ligação não atribua um pty.

View file

@ -481,3 +481,6 @@ workspaceNameDescription=Отображаемое имя рабочей обла
workspacePath=Путь к рабочему пространству
workspacePathDescription=Расположение каталога данных рабочей области
workspaceCreationAlertTitle=Создание рабочего пространства
developerForceSshTty=Принудительный SSH TTY
developerForceSshTtyDescription=Заставь все SSH-соединения выделять pty, чтобы проверить поддержку отсутствующего stderr и pty.
ttyWarning=Соединение принудительно выделило pty/tty и не предоставляет отдельный поток stderr.\n\nЭто может привести к нескольким проблемам.\n\nЕсли можешь, попробуй сделать так, чтобы команда подключения не выделяла pty.

View file

@ -482,3 +482,6 @@ workspaceNameDescription=Çalışma alanının görünen adı
workspacePath=Çalışma alanı yolu
workspacePathDescription=Çalışma alanı veri dizininin konumu
workspaceCreationAlertTitle=Çalışma alanı oluşturma
developerForceSshTty=SSH TTY'yi Zorla
developerForceSshTtyDescription=Eksik bir stderr ve bir pty desteğini test etmek için tüm SSH bağlantılarının bir pty ayırmasını sağlayın.
ttyWarning=Bağlantı zorla bir pty/tty ayırmış ve ayrı bir stderr akışı sağlamıyor.\n\nBu durum birkaç soruna yol açabilir.\n\nEğer yapabiliyorsanız, bağlantı komutunun bir pty tahsis etmemesini sağlayın.

View file

@ -481,3 +481,6 @@ workspaceNameDescription=工作区的显示名称
workspacePath=工作区路径
workspacePathDescription=工作区数据目录的位置
workspaceCreationAlertTitle=创建工作区
developerForceSshTty=强制 SSH TTY
developerForceSshTtyDescription=让所有 SSH 连接都分配一个 pty以测试对缺失的 stderr 和 pty 的支持。
ttyWarning=连接强行分配了 pty/tty且未提供单独的 stderr 流。\n\n这可能会导致一些问题。\n\n如果可以请考虑让连接命令不分配 pty。