Skip to content

Add drag-tab-to-pane-split#11404

Open
vascodegraaff wants to merge 3 commits into
warpdotdev:masterfrom
vascodegraaff:vasco/drag-tab-to-pane-split
Open

Add drag-tab-to-pane-split#11404
vascodegraaff wants to merge 3 commits into
warpdotdev:masterfrom
vascodegraaff:vasco/drag-tab-to-pane-split

Conversation

@vascodegraaff
Copy link
Copy Markdown

@vascodegraaff vascodegraaff commented May 20, 2026

Description

Adds a new UX for splitting tabs: drag a tab from the vertical tabs panel and drop it onto another tab's pane area to create a directional split.

Behavior

  • Cursor's closest edge of the destination pane picks the split direction (left / right / up / down).
  • A translucent half-pane overlay (using theme.surface_overlay_2 / theme.split_pane_border_color) previews where the new pane will land during the drag.
  • The view stays on the user's current tab throughout the drag. Dragging the active tab onto its own pane is a no-op (the destination would always be the active tab's own panes).
  • The empty area below the last tab in the vertical tabs panel acts as a drop target: dropping there appends the source pane as a new tab, with the standard blue insertion indicator rendered directly under the last tab.
  • The live terminal session is transplanted, not respawned — running processes, scrollback, working directory, and cursor state all survive the move.

Out of scope (deferred to follow-ups)

  • Source tabs with internal splits (drag is a no-op).
  • Non-terminal pane content types (no-op).
  • Cross-window tab-to-pane splits (existing DragTabsToWindows flow handles cross-window detach unchanged).
  • Animation on overlay appear/disappear.

Gated behind a new DragTabToPaneSplit feature flag (off by default — dark merge).

How

  • New FeatureFlag::DragTabToPaneSplit variant, registered in app/src/features.rs behind a drag_tab_to_pane_split Cargo feature.
  • New pub(crate) PaneGroup::add_existing_pane_visible(...) helper next to add_pane_as_hidden, wrapping add_pane_with_options for cross-PaneGroup transplant.
  • Workspace tracks last_tab_drag and current_drag_target_pane; on_tab_drag and the DropTab arm coordinate hit-testing, cross-window suppression, and the actual drop via try_drop_tab_on_pane.
  • find_drop_target_pane is restricted to the active tab only. Pane positions are cached indefinitely and never cleared when a PaneGroup unmounts, so iterating over every tab would match stale rects from previously-active tabs and route the drop to the wrong destination.
  • on_tab_drag suppresses its reorder block when the cursor is hovering over another tab's pane area. Without this, the source tab would get swapped into the destination tab's slot and active_tab_index would flip, which then makes the follow-up drop reject (src_idx == active_tab_index).
  • The hit-test reuses the existing SavePosition for panes (pane_id.position_id()).
  • The transplant reuses PaneGroup::remove_pane_for_move (which calls detach(DetachType::Moved) to preserve session state) and remove_tab_without_undo.
  • vertical_tabs.rs unlocks horizontal drag when either DragTabsToWindows or DragTabToPaneSplit is enabled, and renders a tall tail drop zone (with the existing insertion-indicator slot at the top) below the last tab so the empty area below catches drops cleanly without flicker.
  • Direction enum gains PartialEq, Eq so the workspace can diff drag-target state across frames.

Linked Issue

Closes #8959.

  • The linked issue is labeled ready-to-spec or ready-to-implement.

(Issue #8959 is labeled enhancement / triaged / area:window-tabs-panes. Flagging in case maintainers want to add ready-to-implement retroactively — I picked this up because it matched what I wanted to build personally.)

Testing

  • I have manually tested my changes locally with ./script/run --features drag_tab_to_pane_split

Manual test matrix walked through:

  • 4 directions (left/right/up/down) — all produce correct splits.
  • Source has internal split → no-op.
  • Drag the active tab onto its own pane → no-op (view stays put).
  • Drop on chrome / non-pane area → no-op.
  • Drop in the empty area below the last tab in the vertical panel → new tab appended; blue indicator shows directly under the last tab during drag; no flicker.
  • Flag off → all existing tab-drag behavior unchanged.
  • Live terminal state (typed input, running process) survives the move.

Automated tests

Integration tests added in crates/integration/src/test/workspace.rs, gated on a new drag_tab_to_pane_split feature in the integration crate (forwards to warp/drag_tab_to_pane_split). Registered in bin/integration.rs and tests/integration/ui_tests.rs:

  • test_drag_tab_to_pane_split_right — happy path: 2 tabs, drag non-active onto active's pane right-half → 1 tab with 2 panes; both terminals' block history is intact (verifies the DetachType::Moved session preservation).
  • test_drag_tab_to_pane_split_down — direction picking: drop on bottom half → panes stack vertically (verified by inspecting rendered pane rects).
  • test_drag_tab_to_pane_split_source_with_split_is_noop — source tab has 2 panes → drop rejected, workspace unchanged.
  • test_drag_tab_to_pane_split_active_self_drop_is_noop — drag active tab onto its own pane → drop rejected (covers the src_idx == active_tab_index guard added above).

Run a single test directly:

cargo run -p integration --bin integration --features drag_tab_to_pane_split -- test_drag_tab_to_pane_split_right

Or via nextest:

cargo nextest run --no-fail-fast --workspace --features integration/drag_tab_to_pane_split test_drag_tab_to_pane_split

Screenshots / Videos

Screen.Recording.2026-05-26.at.4.02.30.PM.mov

Agent Mode

  • Warp Agent Mode — this PR was created via Claude Code (Anthropic CLI). Happy to discuss any design decisions or rework as needed; the planning + implementation transcript is available on request.

CHANGELOG-IMPROVEMENT: You can now drag a tab from the left vertical tabs panel and drop it onto another tab's pane area to create a directional split, behind the drag_tab_to_pane_split feature flag.

Lets users drag a tab from the vertical tabs panel and drop it onto another
tab's pane area to create a directional split (left/right/up/down). The
destination pane is computed from the cursor's closest edge, and a translucent
half-pane overlay previews where the new pane will land during drag. When the
source is the currently-active tab, the workspace auto-switches to the
previous MRU tab so the user has a visible destination; the original active
tab is restored if the drop is cancelled.

Gated behind a new `DragTabToPaneSplit` feature flag (off by default).

Co-Authored-By: Warp <agent@warp.dev>
@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented May 20, 2026

Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @vascodegraaff on file. In order for us to review and merge your code, each contributor must visit https://cla.warp.dev to read and agree to our CLA. Once you have done so, please comment @cla-bot check to trigger another check.

@github-actions github-actions Bot added the external-contributor Indicates that a PR has been opened by someone outside the Warp team. label May 20, 2026
@vascodegraaff
Copy link
Copy Markdown
Author

/oz-review

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 26, 2026

@vascodegraaff

This PR is not linked to an issue that is marked with ready-to-implement.

Issue-state enforcement details:

Readiness check:

To continue, link this PR to a same-repo issue such as Closes #123 in the PR description, and make sure that issue has ready-to-implement.

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vascodegraaff

This PR is not linked to an issue that is marked with ready-to-implement.

Issue-state enforcement details:

  • Associated same-repo issues checked: #8959

  • Required readiness label: ready-to-implement

Readiness check:

  • #8959: missing ready-to-implement; readiness labels present: none

To continue, link this PR to a same-repo issue such as Closes #123 in the PR description, and make sure that issue has ready-to-implement.

Powered by Oz

Fixes a wrong-target overlay regression that landed with the initial
PR: `find_drop_target_pane` iterated over every tab and asked
`element_position_by_id` for each pane's rect. Pane positions are
cached indefinitely and are never cleared when a `PaneGroup` unmounts,
so panes from previously-active tabs returned stale rects that could
match the cursor and route the drop to the wrong destination tab. The
lookup is now restricted to the active tab — the only tab whose panes
are actually in the rendered view tree.

Suppresses the tab-reorder block in `on_tab_drag` when the drag is
hovering over another tab's pane area. Without this guard, the
reorder logic swaps the source tab into the destination tab's slot
and flips `active_tab_index`, which then makes `find_drop_target_pane`
reject the follow-up drop because `src_idx == active_tab_index`.

Drops the iTerm-style auto-switch-to-MRU-previous behavior that the
initial PR added. The view now stays on the user's current tab
throughout the drag; dragging the active tab onto its own pane is a
no-op.

Adds a tall tail drop-zone below the last tab in the vertical tabs
panel so the empty area catches pane-header drags as "append new
tab" with the existing blue insertion indicator at the top. Kills
the flicker caused by the cursor leaving the small per-tab
`insert_after_index` sliver into a no-drop-target gap.

Adds integration tests in `crates/integration` covering the happy
path (Right split), one non-Right direction (Down split via cursor
position on the bottom half of the destination pane), and two no-op
cases (source tab has an internal split; dragging the active tab
onto its own pane). Gated on a new `drag_tab_to_pane_split` Cargo
feature in the integration crate that forwards to the warp crate.
@cla-bot cla-bot Bot added the cla-signed label May 26, 2026
@vascodegraaff vascodegraaff marked this pull request as ready for review May 26, 2026 09:43
…ane-split

# Conflicts:
#	crates/integration/src/test/workspace.rs
Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vascodegraaff

This PR is not linked to an issue that is marked with ready-to-implement.

Issue-state enforcement details:

  • Associated same-repo issues checked: #8959

  • Required readiness label: ready-to-implement

Readiness check:

  • #8959: missing ready-to-implement; readiness labels present: none

To continue, link this PR to a same-repo issue such as Closes #123 in the PR description, and make sure that issue has ready-to-implement.

Powered by Oz

@vascodegraaff
Copy link
Copy Markdown
Author

/oz-review who can i ping about updating the status of the issue?

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vascodegraaff

This PR is not linked to an issue that is marked with ready-to-implement.

Issue-state enforcement details:

  • Associated same-repo issues checked: #8959

  • Required readiness label: ready-to-implement

Readiness check:

  • #8959: missing ready-to-implement; readiness labels present: none

To continue, link this PR to a same-repo issue such as Closes #123 in the PR description, and make sure that issue has ready-to-implement.

Powered by Oz

@vascodegraaff
Copy link
Copy Markdown
Author

@vascodegraaff

This PR is not linked to an issue that is marked with ready-to-implement.

Issue-state enforcement details:

Readiness check:

To continue, link this PR to a same-repo issue such as Closes #123 in the PR description, and make sure that issue has ready-to-implement.

Powered by Oz

who can i tag to update this? @oz-agent

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed external-contributor Indicates that a PR has been opened by someone outside the Warp team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow merging existing tabs into split pane

1 participant