Repository: zellij-org/zellij
File: src/errors.rs (Rust)

Code before:
            backtrace
        ),
        (None, Some(msg)) => format!(
            "thread '{}' panicked at '{}'\n{:#?}\n{:?}",
            thread, msg, err_ctx, backtrace
        ),
        (None, None) => format!(
            "thread '{}' panicked\n{:#?}\n{:?}",
            thread, err_ctx, backtrace
        ),
    };

    if thread == "main" {
        println!("{}", backtrace);
        process::exit(1);
    } else {
        err_ctx.add_call("panic_hook(handle_panic)");
        send_app_instructions
            .send((err_ctx, AppInstruction::Error(backtrace)))
            .unwrap();
    }
}

#[derive(Clone, Debug)]
pub struct ErrorContext {
    calls: Vec<String>,
}

impl ErrorContext {
    pub fn new() -> Self {
        Self { calls: Vec::new() }
    }

    pub fn add_call(&mut self, call: &str) {
        self.calls.push(call.into());
        OPENCALLS.with(|ctx| *ctx.borrow_mut() = self.clone());
    }
}


Review comment (performance):
A few things about this:
1. Can we change `String` here to work with the instruction types we already have? eg. something like `enum { ScreenInstruction, PtyInstruction, AppInstruction }` - I think that will both help performance and prevent overzealous developers from adding weird stuff to this in the future :)
2. Speaking about performance, while I definitely understand why it makes sense for this to be a `Vec` - I think in our case it might be a bit of an issue. Ideally, I would like this type to be `Copy`, because we would be copying it around A LOT (every event we get from the pty, for example, which is every character print, every style change, etc. if we're printing 10000 lines to the terminal, we will really feel this). And of course, we can't do this with a vec... So I was thinking maybe make this a fixed size array. We'll have it as a separate const type (maybe call it something like `MAX_THREAD_CALL_STACK`), we'll set its length to the maximum we have now (I guess it's 3? 4?) and in the future we can make it larger if we need to. What do you think?

Code after:
            err_ctx,
            thread,
            location.file(),
            location.line(),
            backtrace
        ),
        (None, Some(msg)) => format!(
            "{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked at '{}'\n\u{1b}[0;0m{:?}",
            err_ctx, thread, msg, backtrace
        ),
        (None, None) => format!(
            "{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked\n\u{1b}[0;0m{:?}",
            err_ctx, thread, backtrace
        ),
    };

    if thread == "main" {
        println!("{}", backtrace);
        process::exit(1);
    } else {
        send_app_instructions
            .send(AppInstruction::Error(backtrace))
            .unwrap();
    }
}

#[derive(Clone, Copy)]
pub struct ErrorContext {
    calls: [ContextType; MAX_THREAD_CALL_STACK],
}

impl ErrorContext {
    pub fn new() -> Self {
        Self {
            calls: [ContextType::Empty; MAX_THREAD_CALL_STACK],
        }
    }

    pub fn add_call(&mut self, call: ContextType) {
        for ctx in self.calls.iter_mut() {
            if *ctx == ContextType::Empty {
                *ctx = call;
                break;
            }
        }
        OPENCALLS.with(|ctx| *ctx.borrow_mut() = *self);
    }
}

impl Display for ErrorContext {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {