Skip to content

"Failed to find tab with index" when renaming after deleting tabs with plugin api. #3535

@Pytness

Description

@Pytness

Basic information

Version: zellij 0.40.1
uname -av: Linux *** 5.15.146.1-microsoft-standard-WSL2 #1 SMP Thu Jan 11 04:09:03 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

Issue description

Creating and deleting tabs through the plugin api may cause zellij to misreport their position

Minimal reproduction

Here is an example using a timer to allow zellij to assimilate what is happening and report tab updates:

#[derive(Default, Debug)]
struct TimerState {
    index: usize,
}

impl TimerState {
    fn new() -> Self {
        Self { index: 0 }
    }

    fn next(&mut self) -> bool {
        let mut running = true;

        match self.index {
            // We start with the default tab
            //
            0 => new_tab(), // 2 << Rename this

            1 => new_tab(), // 3 << Delete this
            2 => new_tab(), // 4 << Delete this

            4 => new_tab(), // 5 << Try renaming this
            5 => new_tab(), // 6 << Renaming this renames 3

            // expected state: ["1", "2", "3", "4", "5", "6"]
            9 => rename_tab(1 + 1, "this is the second tab".to_string()),

            // expected state: ["1", "second", "3", "4", "5", "6"]

            // delete the third tab
            10 => {
                go_to_tab(2);
                close_focused_tab();
            }

            // delete the third tab again
            11 => {
                go_to_tab(2);
                close_focused_tab();
            }

            // expected state: ["1", "second",  "5", "6"]

            // // rename the fourth tab
            // // We deleted the third tab, so the fourth tab is now the third tab
            12 => rename_tab(2 + 1, "this is the third tab".to_string()),

            // expected state: ["1", "second", "third", "6"]

            // rename the fourth tab
            13 => rename_tab(3 + 1, "this is the fourth tab".to_string()),
            // expected state: ["1", "second", "third", "fourth"]]

            // rename the fith tab
            14 => rename_tab(4 + 1, "this is the fith tab".to_string()),

            // expected state: ["1", "second", "third", "fourth"]]
            // observed state: ["1", "second", "fith",  "6"]]
            // Reported state of the tabs is not the same as the expected state
            // DEBUG  |...| 2024-08-01 15:51:51.109 [id: 1     ] Tab: pos 0,  name: "Tab #1"
            // DEBUG  |...| 2024-08-01 15:51:51.109 [id: 1     ] Tab: pos 1,  name: "this is the second tab"
            // DEBUG  |...| 2024-08-01 15:51:51.109 [id: 1     ] Tab: pos 2,  name: "this is the fith tab"
            // DEBUG  |...| 2024-08-01 15:51:51.109 [id: 1     ] Tab: pos 3,  name: "Tab #6"
            15 => {
                running = false;
            }

            _ => {}
        }

        self.index += 1;

        running
    }
}


impl ZellijPlugin for State {
    fn load(&mut self, configuration: BTreeMap<String, String>) {
        // we need the ReadApplicationState permission to receive the ModeUpdate and TabUpdate
        // events
        // we need the ChangeApplicationState permission to Change Zellij state (Panes, Tabs and UI)
        request_permission(&[
            PermissionType::ReadApplicationState,
            PermissionType::ChangeApplicationState,
        ]);

        self.config = Config::from_configuration(configuration);

        subscribe(&[
            EventType::PaneUpdate,
            EventType::TabUpdate,
            EventType::Key,
            EventType::Timer,
        ]);
    }

    fn update(&mut self, event: Event) -> bool {
        if !self.initialized {
            self.initialize = true;
            set_timeout(0.5);
        }

        match event {
            Event::Timer(_) => {
                if self.timer.next() {
                    set_timeout(0.5);
                };
            }
	}
    }
    // ...
}

Other relevant information

asciicast

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions