Skip to content

feat: awareness marker for suppressed panes in the active tab (#118) - #121

Merged
GeneralD merged 12 commits into
mainfrom
feat/118-suppressed-marker
Jul 15, 2026
Merged

feat: awareness marker for suppressed panes in the active tab (#118)#121
GeneralD merged 12 commits into
mainfrom
feat/118-suppressed-marker

Conversation

@GeneralD

@GeneralD GeneralD commented Jul 15, 2026

Copy link
Copy Markdown
Owner

agent type complexity closes relates

Closes #118.

The active tab (⌘2) hides a suppressed pane behind its full-width git pane, so that pane carries a in its bottom-right corner; the inactive tabs stay clean.

Three-row tab bar — the active tab's git pane shows a ◳ suppressed marker

Zoomed — the marker on the cover pane

Zoom of the active tab: the ◳ marker sits at the git pane's bottom-right corner

What & why

A suppressed pane is one hidden behind the pane that replaced its slot — e.g. edit-scrollback opens $EDITOR over the current pane, or new-pane --in-place suspends the pane it replaces. The floating-panes work (#110/#112, focus ring #116) deliberately left suppressed panes out of scope, so today they leave no trace on the bar.

This PR adds a small awareness marker () in the active tab's minimap on any tiled pane that hides a suppressed pane behind it — signalling "something is stashed behind this pane" without trying to depict the hidden layout. It answers existence, not contents.

Design decisions (per spec)

  • Presence only — one marker per cover pane, no counts, even when several panes are suppressed behind the same cover.
  • Active tab only — inactive tabs stay quiet, avoiding flicker from transient suppresses.
  • Always on, no config flag — the feature reads only is_suppressed (already within the existing ReadApplicationState grant), so it adds no new zellij permission and can't trigger the #15 bar-freeze trap.
  • Draw only — no click handler; the click-resolution order is unchanged.

How it works

A suppressed pane stays in the PaneManifest sharing its cover pane's exact rect (spike-verified against zellij 0.44.3 — see rule #19). So the cover is found by pure geometry: the tiled pane whose rectangle contains a suppressed pane's rectangle.

  • projection.rsis_suppressed_terminal (is_suppressed && !is_plugin) + project_suppressed(), mirroring project_floating(). The #110 tiled filter is_tiled_terminal is unchanged (byte-identity preserved).
  • suppressed.rs (new) — dependency-free cover_ids(suppressed, tiled) containment matcher, unit-tested off-wasm.
  • minimap.rs — stamps the glyph in the cover pane's bottom-right cell, in that pane's ring shade. A cell already reserved by a hidden-float chip (feat: show floating panes in the minimap, selectable when hidden #110) is skipped — the chip owns its corner.
  • lib.rs — computes the cover set for the active tab only and threads it through paint::bar → tab_block::assemble → minimap::render.

Testing

  • CARGO_BUILD_TARGET=aarch64-apple-darwin cargo test --lib314 passing (new: cover-matcher geometry, suppressed projection, marker render, and the chip-vs-marker corner-precedence regression).
  • cargo clippy --target wasm32-wasip1 --all-features --lib → clean.
  • cargo build --target wasm32-wasip1 → builds.
  • cargo run --example render_floating --target aarch64-apple-darwin → the visual above.

Deferred (out of scope, per spec §9)

Full layout depiction of the suppressed pane, reveal/focus from the bar, inactive-tab display, and hidden-count display — all stay deferred.

Summary by CodeRabbit

  • New Features

    • Added an awareness marker to the active tab’s minimap when visible panes conceal suppressed background panes.
    • Markers appear in the covering pane’s corner and respect existing labels and floating-pane indicators.
    • Added an example demonstrating suppressed-pane markers.
  • Documentation

    • Documented suppressed-pane geometry, filtering guidance, verification steps, and marker behavior.
    • Added design and implementation plans for suppressed-pane awareness.

GeneralD added 9 commits July 16, 2026 00:30
Stamp SUPPRESSED_MARKER_GLYPH in a cover pane's block-local bottom-right
cell when it hides a suppressed pane, using the cover pane's own ring
shade so the cue reads against its fill. The marker takes priority over
a same-cell label (never overprinted) but yields to a hidden-float chip
sharing the same corner.

render() gains a new `suppressed_covers: &[usize]` parameter (last arg);
every existing call site now passes `&[]`, keeping prior output byte-
identical.
Thread a per-tab suppressed_covers list from State::render through
paint::bar and tab_block::assemble/grid_lines down to minimap::render,
populated for the active tab only so the marker cue shows on the tab
you're currently viewing.
Copilot AI review requested due to automatic review settings July 15, 2026 16:33
@GeneralD GeneralD self-assigned this Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@GeneralD, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 36 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 326d0659-3183-49db-b920-3c5efe3459ee

📥 Commits

Reviewing files that changed from the base of the PR and between 6d11d4e and 141d7c9.

📒 Files selected for processing (10)
  • examples/render_active_cue.rs
  • examples/render_close_button.rs
  • examples/render_demo.rs
  • examples/render_gradient.rs
  • examples/render_new_tab_button.rs
  • examples/render_palette.rs
  • examples/render_perspective.rs
  • examples/render_top_label.rs
  • src/minimap.rs
  • src/projection.rs
📝 Walkthrough

Walkthrough

Adds active-tab suppressed-pane awareness to the tab minimap. Suppressed terminal panes are projected, matched to containing tiled panes, and rendered as corner glyphs while preserving hidden-float chip precedence. The change also wires state through the bar renderer and documents the geometry behavior.

Changes

Suppressed Pane Awareness

Layer / File(s) Summary
Marker design and geometry contract
.claude/rules/..., docs/superpowers/...
Documents suppressed-pane geometry, terminal filtering, active-tab scope, marker placement, precedence, validation, and implementation phases.
Suppressed projection and cover matching
src/projection.rs, src/suppressed.rs
Projects suppressed non-plugin terminals into PaneRect values and returns tiled pane IDs containing their rectangles, with unit tests for filtering, deduplication, and unmatched geometry.
Minimap marker rendering
src/minimap.rs
Adds suppressed-cover inputs, draws the marker in the cover pane’s bottom-right cell, and lets hidden-float chips take precedence.
Rendering pipeline wiring and example
src/lib.rs, src/paint.rs, src/tab_block.rs, examples/render_floating.rs
Builds active-tab cover mappings, threads them through bar and tab-block rendering, updates call sites, and demonstrates the marker state.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant StateRender
  participant Projection
  participant CoverMatcher
  participant PaintBar
  participant MinimapRender
  StateRender->>Projection: project suppressed and tiled panes
  Projection->>CoverMatcher: pass pane rectangles
  CoverMatcher-->>StateRender: return cover pane IDs
  StateRender->>PaintBar: pass IDs by tab position
  PaintBar->>MinimapRender: pass IDs for active tab
  MinimapRender-->>PaintBar: draw suppressed marker
Loading

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR matches #118 by adding a dependency-free corner marker for suppressed panes in the active tab, with containment-based matching and no interaction.
Out of Scope Changes check ✅ Passed No unrelated code changes stand out; the added docs and example wiring support the suppressed-pane marker work.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding an awareness marker for suppressed panes in the active tab.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/118-suppressed-marker

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an “awareness” cue for suppressed/background panes by marking the cover tiled pane in the active tab’s minimap, without introducing new permissions or interactions. This extends the existing minimap projection/render pipeline (and the “dependency-free pure layer” pattern used for floating panes) to include suppressed-pane detection and a small corner glyph marker.

Changes:

  • Add suppressed-pane projection + dependency-free geometry matcher to compute “cover pane” ids.
  • Thread per-tab suppressed-cover ids through lib → paint → tab_block → minimap and render a marker in the cover pane’s bottom-right cell (with chip precedence).
  • Add docs/spec/plan updates and extend the floating render example to demonstrate the marker.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/tab_block.rs Threads suppressed-cover ids into minimap rendering.
src/suppressed.rs New pure helper module to match suppressed panes to their cover pane(s).
src/projection.rs Adds suppressed-pane projection from PaneInfo to PaneRect.
src/paint.rs Plumbs suppressed-cover ids per tab into tab_block::assemble.
src/minimap.rs Renders suppressed cover markers in-pane, with chip precedence.
src/lib.rs Computes suppressed cover ids for the active tab and passes them to paint.
examples/render_floating.rs Demonstrates the suppressed marker in the visual render example.
docs/superpowers/specs/2026-07-16-suppressed-pane-marker-design.md New design spec documenting decisions/spike and rendering rules.
docs/superpowers/plans/2026-07-16-suppressed-pane-marker.md New implementation plan documenting the steps and rationale.
.claude/rules/zellij-plugin-development.md Adds a verified rule about suppressed panes’ manifest geometry behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/minimap.rs Outdated
Comment on lines +1379 to +1395
// A suppressed-pane marker overrides a same-cell label so the awareness cue
// is never overprinted (like the chip above). Drawn in the cover pane's ring
// shade so it contrasts with its own fill (reusing the #47/#116 ring
// vocabulary). Markers are passed for the active tab only, so no inactive blend.
if let Some((_, _, cover_id)) = suppressed_marks
.iter()
.find(|(mc, mr, _)| *mc == c && *mr == tr)
{
let fill = pixel_color(&grid, &ring, panes, palette, &sweeps, pw, c, 2 * tr);
match fill {
Some(f) => put_bg(&mut out, f),
None => put_default_bg(&mut out),
}
put_fg(&mut out, palette.ring_for(*cover_id));
out.push(crate::suppressed::SUPPRESSED_MARKER_GLYPH);
continue;
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

agent action

Fixed in 7cf6336. The marker now yields to a visible float that owns the cell (cell_covered) and falls through to the float paint path, and it darkens its background in the drop-shadow band like the fill beneath it — so it no longer punches through a float or its shadow. Regression test: a_visible_float_occludes_the_suppressed_marker.

Comment thread src/paint.rs
Comment on lines 43 to 55
pub fn bar(
rows: usize,
layout: &LineLayout,
panes_by_position: &BTreeMap<usize, Vec<PaneRect>>,
palette: &Palette,
prefix: &str,
gradient: GradientSpec,
inactive_dim: bool,
perspective: bool,
close: Close,
floats_by_position: &BTreeMap<usize, crate::floating::FloatSpec>,
suppressed_covers_by_position: &BTreeMap<usize, Vec<usize>>,
) -> String {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

agent action

Fixed in 7afb246. Every example caller now passes the suppressed-cover argument — render_demo, render_active_cue, render_close_button, render_perspective, render_new_tab_button, render_top_label, render_palette (for paint::bar) and render_gradient (for minimap::render) — so cargo build --examples is green again.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6d11d4ee6d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/paint.rs
perspective: bool,
close: Close,
floats_by_position: &BTreeMap<usize, crate::floating::FloatSpec>,
suppressed_covers_by_position: &BTreeMap<usize, Vec<usize>>,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Update example callers for the new render arguments

This new required argument was only propagated through library/test call sites and render_floating; I checked examples with rg "paint::bar\\(|render\\(" examples and the other demos still call the old arity (render_gradient.rs for minimap::render, plus render_demo.rs, render_perspective.rs, render_close_button.rs, render_active_cue.rs, render_new_tab_button.rs, and render_top_label.rs for paint::bar). Users running any of those examples will hit a compile error, so please pass an empty suppressed-cover slice/map there as well.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

agent action

Fixed in 7afb246. Updated all example callers to pass the suppressed-cover argument (also caught render_palette, which wasn't in the list). cargo build --examples passes.

Comment thread src/minimap.rs Outdated
Comment on lines +1393 to +1394
out.push(crate::suppressed::SUPPRESSED_MARKER_GLYPH);
continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Let visible floats cover suppressed markers

When floating=hybrid and the active tab's float layer is visible, this marker branch still pushes and continues before the later visible-float paint path can run. A float whose projected rect covers the cover-pane corner will therefore be drawn underneath the marker, while router::route_click still gives that same cell to float_overlay_at before tiled panes; please treat float-covered marker cells like occluded cells and let them fall through to the float overlay.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

agent action

Fixed in 7cf6336. The marker branch now yields when cell_covered[..] is set (a visible float owns the cell) and falls through so the float overlay paints it — matching the tiled-label occlusion order. Test: a_visible_float_occludes_the_suppressed_marker.

Comment thread src/minimap.rs Outdated
Comment on lines +1393 to +1394
out.push(crate::suppressed::SUPPRESSED_MARKER_GLYPH);
continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reserve marker cells from wide labels

When a two-column title lands so its continuation cell is the pane's bottom-right marker cell (for example, a two-text-row pane with a CJK label ending at px1), the wide glyph emitted in the previous column has already advanced through this cell, but this branch still emits before LabelDraw::Skip can preserve the row width. That shifts the rest of the row and breaks the renderer's one-visible-cell-per-column invariant; the marker cell should be reserved from label placement the way chip and close cells are, or skipped when it is a continuation.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

agent action

Fixed in 7cf6336. The marker now yields when its cell is a wide glyph's continuation (LabelDraw::Skip), falling through to the label Skip arm that emits nothing — so the one-visible-cell-per-column invariant is preserved.

Comment thread src/minimap.rs Outdated
Comment on lines +1392 to +1393
put_fg(&mut out, palette.ring_for(*cover_id));
out.push(crate::suppressed::SUPPRESSED_MARKER_GLYPH);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid drawing marker foreground in the ring color

When the cover pane is focused in the active tab — the common edit-scrollback case — the chosen bottom-right marker cell is on the focus-ring edge, so pixel_color returns palette.ring_for(cover_id) for the background and this line uses the same color for the glyph foreground. The marker then renders foreground-on-background in the same RGB and effectively disappears; use a contrasting foreground or sample the pane fill without the focus ring for this cell.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

agent action

Fixed in 7cf6336. The marker background is now sampled from the pane fill (fill_at) instead of pixel_color (which returns the ring on a focused cover's border), so the ring-shade glyph always contrasts — including the common focused edit-scrollback cover. Test: a_focused_cover_marker_stays_legible asserts fg ≠ bg.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/minimap.rs`:
- Around line 1379-1395: Update the suppressed-marker branch in the minimap
rendering flow so markers yield to visible floating panes and still pass through
the floating-layer draw step, including drop-shadow handling. Do not
unconditionally draw the marker and continue before `float_px`; match the
existing tiled-label ordering and occlusion behavior, preserving marker
rendering only where no visible float covers the cell.

In `@src/projection.rs`:
- Around line 106-136: Update is_suppressed_terminal to require suppressed,
non-plugin panes that are not floating, matching the tiled-pane filtering
semantics. Keep project_suppressed using this predicate, and update its
associated test to verify suppressed floating panes are excluded while
suppressed tiled panes remain projected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b339be90-ac50-497e-9f96-af5773bbbfe4

📥 Commits

Reviewing files that changed from the base of the PR and between d487907 and 6d11d4e.

📒 Files selected for processing (10)
  • .claude/rules/zellij-plugin-development.md
  • docs/superpowers/plans/2026-07-16-suppressed-pane-marker.md
  • docs/superpowers/specs/2026-07-16-suppressed-pane-marker-design.md
  • examples/render_floating.rs
  • src/lib.rs
  • src/minimap.rs
  • src/paint.rs
  • src/projection.rs
  • src/suppressed.rs
  • src/tab_block.rs

Comment thread src/minimap.rs Outdated
Comment thread src/projection.rs
GeneralD added 3 commits July 16, 2026 01:51
… labels (#118)

The marker short-circuited before the label/float paint step, so it:
- punched through a visible float that covered its cell (spec §7.1),
- ignored the float drop-shadow band,
- overrode a wide label's continuation cell, breaking row width, and
- sampled the focus ring for both fg and bg on a focused cover, hiding itself.

It now yields to cell_covered floats and LabelDraw::Skip continuations, takes
the drop-shadow, and samples the pane fill (not the ring) for its background.
#118)

Cover-matching runs against the tiled set only, so a suppressed float has no
cover to match and could false-match an unrelated tiled pane whose geometry
contains it. Drop floats from is_suppressed_terminal, making it the true
suppressed sibling of is_tiled_terminal.
@GeneralD
GeneralD merged commit eefcd45 into main Jul 15, 2026
5 checks passed
@GeneralD
GeneralD deleted the feat/118-suppressed-marker branch July 15, 2026 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: depict suppressed / background panes in the tab minimap

2 participants