Skip to content

Multi-terminal bug: widget state recycling causes wrong column count on tab switch #67

@felixn678

Description

@felixn678

Bug Description

When using multiple Terminal instances (e.g., in a tabbed or split-pane app), switching between terminals causes the non-first terminal to display with an incorrect column count (~10 columns instead of 80+). The shell prompt appears truncated/garbled and keyboard input renders incorrectly.

Only the first terminal works correctly. All subsequent terminals have this issue.

Root Cause

In view.rs, the resize check at line 590-599:

let state = tree.state.downcast_mut::<TerminalViewState>();
let layout_size = layout.bounds().size();
if state.size != layout_size {
    state.size = layout_size;
    let cmd = Command::Resize(Some(layout_size), Some(self.term.font.measure));
    shell.publish(Event::BackendCall(self.term.id, cmd));
}

When Iced's Tree reconciliation (diff()) recycles widget state from Terminal A for Terminal B (which happens when switching tabs or rearranging panes), state.size already equals layout_size from the previous terminal. The condition state.size != layout_size is false, so the resize command is never sent for the new terminal.

The new terminal's PTY stays at the size set by initial_sync() which calculates floor(80.0 / 8) ≈ 10 columns (because TerminalSize::default() has layout_width=80.0 and cell_width gets updated to ~8 by font measurement).

Steps to Reproduce

  1. Create an app with pane_grid containing multiple Terminal instances (like the split_view example but with tab switching)
  2. Create Terminal #0 → works fine (80+ columns)
  3. Switch to show Terminal make widget from POC #1 in the same pane position → broken (10 columns)

Fix

Track terminal_id in TerminalViewState. When the state is recycled for a different terminal, reset size to zero to force the resize check to fire:

// Add to TerminalViewState:
terminal_id: Option<u64>,

// Add to on_event(), before the size check:
if state.terminal_id != Some(self.term.id) {
    state.terminal_id = Some(self.term.id);
    state.size = Size::from([0.0, 0.0]);
}

This is a 3-line logic change. PR incoming.

Environment

  • iced_term: 0.6.0 (also likely affects 0.7.0 and 0.8.0 — same pattern exists)
  • iced: 0.13.1
  • OS: macOS

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions