From cff4fba81c3fc5fe1377edb779ad33cd190104c9 Mon Sep 17 00:00:00 2001 From: Gregor Lohaus Date: Fri, 19 Jun 2026 16:44:16 +0200 Subject: [PATCH] post create pane sync --- README.md | 2 ++ config.example.toml | 1 + src/main/java/com/gregor/jprototerm/AppConfig.java | 7 ++++++- src/main/java/com/gregor/jprototerm/Compositor.java | 13 +++++++++++++ .../java/com/gregor/jprototerm/TerminalWindow.java | 7 +++++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9729f1b..0ba70e8 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ split_regex = "," # One of: "none", "cd", "create_panes", "create_panes_floating". post_create_action = "none" commands = [] +sync_panes = false [env.override] ZELLIJ_SESSION_NAME = "" @@ -199,6 +200,7 @@ paste = "CTRL+SHIFT+V" `create_panes`, or create one floating pane per worktree with `create_panes_floating`. `worktree.commands`, for example `["npm install", "git status"]`, can run commands in created panes; commands are assigned in order and repeat when fewer commands than panes are created. + `worktree.sync_panes = true` syncs those created panes after the configured commands are sent. - `Alt+y`: enter pane-sync selection mode, commit the selection, or stop an active pane sync - `Space`: toggle the focused pane in the sync set while pane-sync selection mode is active - Once committed, input typed or pasted into any synced pane is mirrored to the other synced panes diff --git a/config.example.toml b/config.example.toml index e620901..0811f36 100644 --- a/config.example.toml +++ b/config.example.toml @@ -25,6 +25,7 @@ split_regex = "," # One of: "none", "cd", "create_panes", "create_panes_floating". post_create_action = "none" commands = [] +sync_panes = false [env.override] ZELLIJ_SESSION_NAME = "" diff --git a/src/main/java/com/gregor/jprototerm/AppConfig.java b/src/main/java/com/gregor/jprototerm/AppConfig.java index e8c634d..2c70f5f 100644 --- a/src/main/java/com/gregor/jprototerm/AppConfig.java +++ b/src/main/java/com/gregor/jprototerm/AppConfig.java @@ -33,6 +33,7 @@ public record AppConfig( String worktreeSplitRegex, String worktreePostCreateAction, List worktreeCommands, + boolean worktreeSyncPanes, String closeSignal, Map envOverride, Map keybindings @@ -83,6 +84,7 @@ public record AppConfig( stringValue(document, "worktree.split_regex", defaults.worktreeSplitRegex), stringValue(document, "worktree.post_create_action", defaults.worktreePostCreateAction), stringListValue(document, "worktree.commands", defaults.worktreeCommands), + booleanValue(document, "worktree.sync_panes", defaults.worktreeSyncPanes), closeSignalValue(document, defaults.closeSignal), envOverride(document, defaults.envOverride), keybindings(document, defaults) @@ -109,6 +111,7 @@ public record AppConfig( ",", "none", List.of(), + false, "SIGTERM", Map.of(), Map.ofEntries( @@ -150,6 +153,7 @@ public record AppConfig( worktreeSplitRegex, worktreePostCreateAction, worktreeCommands, + worktreeSyncPanes, closeSignal, envOverride, keybindings @@ -256,7 +260,8 @@ public record AppConfig( builder.append("relative_worktree_path = ").append(quoted(worktreeRelativePath)).append('\n'); builder.append("split_regex = ").append(quoted(worktreeSplitRegex)).append('\n'); builder.append("post_create_action = ").append(quoted(worktreePostCreateAction)).append('\n'); - builder.append("commands = ").append(quotedList(worktreeCommands)).append("\n\n"); + builder.append("commands = ").append(quotedList(worktreeCommands)).append('\n'); + builder.append("sync_panes = ").append(worktreeSyncPanes).append("\n\n"); builder.append("[env.override]\n"); for (Map.Entry entry : envOverride.entrySet()) { builder.append(entry.getKey()).append(" = ").append(quoted(entry.getValue())).append('\n'); diff --git a/src/main/java/com/gregor/jprototerm/Compositor.java b/src/main/java/com/gregor/jprototerm/Compositor.java index 15a4f67..c74b683 100644 --- a/src/main/java/com/gregor/jprototerm/Compositor.java +++ b/src/main/java/com/gregor/jprototerm/Compositor.java @@ -188,6 +188,19 @@ public final class Compositor { .toList(); } + public void syncPanes(List panes) { + paneSyncSelectMode = false; + paneSyncSelection.clear(); + paneSyncPanes.clear(); + for (TerminalPane pane : panes) { + if (pane != null) { + paneSyncPanes.add(pane); + } + } + prunePaneSyncState(); + layoutVersion++; + } + public void toggleFloating() { mutateCurrentTab(() -> currentTab().toggleFloating()); } diff --git a/src/main/java/com/gregor/jprototerm/TerminalWindow.java b/src/main/java/com/gregor/jprototerm/TerminalWindow.java index 804f490..f72356e 100644 --- a/src/main/java/com/gregor/jprototerm/TerminalWindow.java +++ b/src/main/java/com/gregor/jprototerm/TerminalWindow.java @@ -385,10 +385,14 @@ final class TerminalWindow { private void createWorktreePanes(List worktreePaths, boolean floating) { List commands = config.worktreeCommands(); + List createdPanes = new ArrayList<>(); for (int i = 0; i < worktreePaths.size(); i++) { TerminalPane pane = floating ? compositor.createFloatingPaneInDirectory(worktreePaths.get(i)) : compositor.createTiledPane(worktreePaths.get(i)); + if (pane != null) { + createdPanes.add(pane); + } if (pane != null && !commands.isEmpty()) { String command = commands.get(i % commands.size()); if (command != null && !command.isBlank()) { @@ -396,6 +400,9 @@ final class TerminalWindow { } } } + if (config.worktreeSyncPanes() && !createdPanes.isEmpty()) { + compositor.syncPanes(createdPanes); + } } private List readCreatedWorktreePaths(Path createdFile) {