This commit is contained in:
crschnick
2025-04-12 14:54:53 +00:00
parent ae57c794e9
commit a419d623a1
13 changed files with 47 additions and 5085 deletions
+1 -1
View File
@@ -75,7 +75,7 @@ Especially when starting out, it might be a good idea to start with easy tasks f
### Interacting via the HTTP API
You can create clients that communicate with the XPipe daemon via its HTTP API.
To get started, see the [OpenAPI spec](/openapi.yaml).
To get started, see the [OpenAPI spec](https://docs.xpipe.io/api).
### Implementing support for a new editor
-7
View File
@@ -156,13 +156,6 @@ processResources {
into resourcesDir
}
}
doLast {
copy {
from file("$rootDir/openapi.yaml")
into file("${sourceSets.main.output.resourcesDir}/io/xpipe/app/resources/misc");
}
}
}
distTar {
@@ -31,7 +31,7 @@ public class AboutCategory extends AppPrefsCategory {
@Override
protected Comp<?> create() {
var props = createProperties().padding(new Insets(0, 0, 0, 5));
var update = new UpdateCheckComp().grow(true, false);
var update = new UpdateCheckComp().grow(true, false).prefWidth(600);
return new VerticalComp(List.of(props, Comp.hspacer(8), update, Comp.hspacer(13), Comp.hseparator().padding(Insets.EMPTY)))
.apply(s -> s.get().setFillWidth(true))
.apply(struc -> struc.get().setSpacing(15))
@@ -175,6 +175,7 @@ public class TerminalLauncher {
if (preferTabs) {
var multiplexerConfig = launchMultiplexerTabInNewTerminal(request, terminalConfig, config);
if (multiplexerConfig.isPresent()) {
TerminalMultiplexerManager.registerMultiplexerLaunch(request);
launch(type, multiplexerConfig.get(), latch);
return;
}
@@ -1,19 +1,49 @@
package io.xpipe.app.terminal;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.ThreadHelper;
import java.util.*;
public class TerminalMultiplexerManager {
private static UUID pendingMultiplexerLaunch;
private static final Map<UUID, TerminalMultiplexer> connectionHubRequests = new HashMap<>();
public static void registerMultiplexerLaunch(UUID uuid) {
pendingMultiplexerLaunch = uuid;
var listener = new TerminalView.Listener() {
@Override
public void onSessionOpened(TerminalView.ShellSession session) {
if (session.getRequest().equals(pendingMultiplexerLaunch)) {
pendingMultiplexerLaunch = null;
TerminalView.get().removeListener(this);
}
}
};
TerminalView.get().addListener(listener);
}
public static Optional<TerminalMultiplexer> getEffectiveMultiplexer() {
var multiplexer = AppPrefs.get().terminalMultiplexer().getValue();
return Optional.ofNullable(multiplexer);
}
public static boolean requiresNewTerminalSession(UUID requestUuid) {
// Wait if we are currently opening a new multiplexer
if (pendingMultiplexerLaunch != null) {
// Wait for max 10s
for (int i = 0; i < 100; i++) {
if (pendingMultiplexerLaunch == null) {
break;
}
ThreadHelper.sleep(100);
}
// Give multiplexer a second to start in terminal
ThreadHelper.sleep(1000);
}
var mult = getEffectiveMultiplexer();
if (mult.isEmpty()) {
connectionHubRequests.put(requestUuid, null);
@@ -13,6 +13,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Consumer;
public class TerminalView {
@@ -106,18 +107,23 @@ public class TerminalView {
if (!terminalInstances.contains(tv.get())) {
terminalInstances.add(tv.get());
listeners.forEach(listener -> listener.onTerminalOpened(tv.get()));
forListeners(listener -> listener.onTerminalOpened(tv.get()));
}
var session = new ShellSession(request, shell.get(), tv.get());
sessions.add(session);
listeners.forEach(listener -> listener.onSessionOpened(session));
forListeners(listener -> listener.onSessionOpened(session));
TrackEvent.withTrace("Terminal instance opened")
.tag("terminalPid", terminal.get().pid())
.handle();
}
private void forListeners(Consumer<Listener> consumer) {
var copy = new ArrayList<>(listeners);
copy.forEach(consumer);
}
private Optional<TerminalSession> createTerminalSession(ProcessHandle terminalProcess) {
return switch (OsType.getLocal()) {
case OsType.Linux linux -> Optional.of(new TerminalSession(terminalProcess));
@@ -179,7 +185,7 @@ public class TerminalView {
var alive = session.shell.isAlive() && session.getTerminal().isRunning();
if (!alive) {
sessions.remove(session);
listeners.forEach(listener -> listener.onSessionClosed(session));
forListeners(listener -> listener.onSessionClosed(session));
}
}
@@ -190,7 +196,7 @@ public class TerminalView {
TrackEvent.withTrace("Terminal session is dead")
.tag("pid", terminalInstance.getTerminalProcess().pid())
.handle();
listeners.forEach(listener -> listener.onTerminalClosed(terminalInstance));
forListeners(listener -> listener.onTerminalClosed(terminalInstance));
}
}
}
@@ -38,7 +38,7 @@ public class TmuxTerminalMultiplexer implements TerminalMultiplexer {
"tmux kill-session -t xpipe",
"tmux new-session -d -s xpipe",
"tmux rename-window \"" + escape(config.getDisplayName(), true) + "\"",
"tmux send-keys -t xpipe '" + escape(command, false) + ";exit' Enter",
"tmux send-keys -t xpipe ' " + escape(command, false) + "; exit' Enter",
"tmux attach -d -t xpipe");
}
@@ -30,7 +30,7 @@ public class ZellijTerminalMultiplexer implements TerminalMultiplexer {
return ShellScript.lines(
"zellij attach --create-background xpipe",
"zellij -s xpipe action new-tab --name \"" + escape(config.getDisplayName(), false, true) + "\"",
"zellij -s xpipe action write-chars -- " + escape(command, true, true) + "\\;exit",
"zellij -s xpipe action write-chars -- " + escape(" " + command, true, true) + "\\;exit",
"zellij -s xpipe action write 10",
"zellij -s xpipe action clear"
);
@@ -43,7 +43,7 @@ public class ZellijTerminalMultiplexer implements TerminalMultiplexer {
"zellij delete-session -f xpipe > /dev/null 2>&1",
"zellij attach --create-background xpipe",
"zellij -s xpipe run -c --name \"" + escape(config.getDisplayName(), false, true) + "\" -- "
+ escape(command, false, false),
+ escape(" " + command, false, false),
"zellij attach xpipe");
}
@@ -6,12 +6,9 @@ public class Hyperlinks {
public static final String GITHUB = "https://github.com/xpipe-io/xpipe";
public static final String GITHUB_PTB = "https://github.com/xpipe-io/xpipe-ptb";
public static final String GITHUB_LATEST = "https://github.com/xpipe-io/xpipe/releases/latest";
public static final String GITHUB_PYTHON_API = "https://github.com/xpipe-io/xpipe-python-api";
public static final String TRANSLATE = "https://github.com/xpipe-io/xpipe/tree/master/lang";
public static final String DISCORD = "https://discord.gg/8y89vS8cRb";
public static final String GITHUB_WEBTOP = "https://github.com/xpipe-io/xpipe-webtop";
public static final String SLACK =
"https://join.slack.com/t/XPipe/shared_invite/zt-1awjq0t5j-5i4UjNJfNe1VN4b_auu6Cg";
public static void open(String uri) {
DesktopHelper.openUrl(uri);
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -7,7 +7,7 @@ The XPipe beacon component is responsible for handling all communications betwee
and the APIs and the CLI. It provides an API that supports all kinds
of different operations.
For a full documentation, see the [OpenAPI spec](/../openapi.yaml)
For a full documentation, see the [OpenAPI spec](https://docs.xpipe.io/api)
### Inner Workings
@@ -102,11 +102,6 @@ public class RunScriptActionMenu implements ActionProvider {
public ActionProvider.Action createAction(DataStoreEntryRef<ShellStore> store) {
return new Action(store);
}
@Override
public List<? extends ActionProvider> getChildren(List<DataStoreEntryRef<ShellStore>> batch) {
return List.of();
}
};
}
}
-1140
View File
File diff suppressed because it is too large Load Diff