aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/errors.rs
diff options
context:
space:
mode:
authorKunal Mohan <kunalmohan99@gmail.com>2021-05-16 16:42:50 +0530
committerKunal Mohan <kunalmohan99@gmail.com>2021-05-16 21:41:56 +0530
commit2038947a14d32d89da2bdbcaa1381c3015ac9c7a (patch)
tree5a332470e32b380816098594a89d3c3db1f6eb53 /src/common/errors.rs
parenthandle error on termios initialization (#511) (diff)
downloadsl0ppij-2038947a14d32d89da2bdbcaa1381c3015ac9c7a.tar.gz
sl0ppij-2038947a14d32d89da2bdbcaa1381c3015ac9c7a.tar.xz
sl0ppij-2038947a14d32d89da2bdbcaa1381c3015ac9c7a.zip
Big refactor: separate crates for client, server and utilities
Diffstat (limited to 'src/common/errors.rs')
-rw-r--r--src/common/errors.rs393
1 files changed, 0 insertions, 393 deletions
diff --git a/src/common/errors.rs b/src/common/errors.rs
deleted file mode 100644
index 262dfd6b..00000000
--- a/src/common/errors.rs
+++ /dev/null
@@ -1,393 +0,0 @@
-//! Error context system based on a thread-local representation of the call stack, itself based on
-//! the instructions that are sent between threads.
-
-use serde::{Deserialize, Serialize};
-
-use std::fmt::{Display, Error, Formatter};
-
-use crate::client::ClientInstruction;
-use crate::common::thread_bus::{ASYNCOPENCALLS, OPENCALLS};
-use crate::pty::PtyInstruction;
-use crate::screen::ScreenInstruction;
-use crate::server::ServerInstruction;
-
-/// The maximum amount of calls an [`ErrorContext`] will keep track
-/// of in its stack representation. This is a per-thread maximum.
-const MAX_THREAD_CALL_STACK: usize = 6;
-
-#[cfg(not(test))]
-use super::thread_bus::SenderWithContext;
-#[cfg(not(test))]
-use std::panic::PanicInfo;
-
-pub trait ErrorInstruction {
- fn error(err: String) -> Self;
-}
-
-impl ErrorInstruction for ClientInstruction {
- fn error(err: String) -> Self {
- ClientInstruction::Error(err)
- }
-}
-
-impl ErrorInstruction for ServerInstruction {
- fn error(err: String) -> Self {
- ServerInstruction::Error(err)
- }
-}
-
-/// Custom panic handler/hook. Prints the [`ErrorContext`].
-#[cfg(not(test))]
-pub fn handle_panic<T>(info: &PanicInfo<'_>, sender: &SenderWithContext<T>)
-where
- T: ErrorInstruction + Clone,
-{
- use backtrace::Backtrace;
- use std::{process, thread};
- let backtrace = Backtrace::new();
- let thread = thread::current();
- let thread = thread.name().unwrap_or("unnamed");
-
- let msg = match info.payload().downcast_ref::<&'static str>() {
- Some(s) => Some(*s),
- None => info.payload().downcast_ref::<String>().map(|s| &**s),
- };
-
- let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow());
-
- let backtrace = match (info.location(), msg) {
- (Some(location), Some(msg)) => format!(
- "{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked at '{}': {}:{}\n\u{1b}[0;0m{:?}",
- err_ctx,
- thread,
- msg,
- location.file(),
- location.line(),
- backtrace,
- ),
- (Some(location), None) => format!(
- "{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked: {}:{}\n\u{1b}[0;0m{:?}",
- 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 {
- let _ = sender.send(T::error(backtrace));
- }
-}
-
-pub fn get_current_ctx() -> ErrorContext {
- ASYNCOPENCALLS
- .try_with(|ctx| *ctx.borrow())
- .unwrap_or_else(|_| OPENCALLS.with(|ctx| *ctx.borrow()))
-}
-
-/// A representation of the call stack.
-#[derive(Clone, Copy, Serialize, Deserialize)]
-pub struct ErrorContext {
- calls: [ContextType; MAX_THREAD_CALL_STACK],
-}
-
-impl ErrorContext {
- /// Returns a new, blank [`ErrorContext`] containing only [`Empty`](ContextType::Empty)
- /// calls.
- pub fn new() -> Self {
- Self {
- calls: [ContextType::Empty; MAX_THREAD_CALL_STACK],
- }
- }
-
- /// Adds a call to this [`ErrorContext`]'s call stack representation.
- pub fn add_call(&mut self, call: ContextType) {
- for ctx in self.calls.iter_mut() {
- if *ctx == ContextType::Empty {
- *ctx = call;
- break;
- }
- }
- self.update_thread_ctx()
- }
-
- /// Updates the thread local [`ErrorContext`].
- pub fn update_thread_ctx(&self) {
- ASYNCOPENCALLS
- .try_with(|ctx| *ctx.borrow_mut() = *self)
- .unwrap_or_else(|_| OPENCALLS.with(|ctx| *ctx.borrow_mut() = *self));
- }
-}
-
-impl Default for ErrorContext {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl Display for ErrorContext {
- fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
- writeln!(f, "Originating Thread(s):")?;
- for (index, ctx) in self.calls.iter().enumerate() {
- if *ctx == ContextType::Empty {
- break;
- }
- writeln!(f, "\u{1b}[0;0m{}. {}", index + 1, ctx)?;
- }
- Ok(())
- }
-}
-
-/// Different types of calls that form an [`ErrorContext`] call stack.
-///
-/// Complex variants store a variant of a related enum, whose variants can be built from
-/// the corresponding Zellij MSPC instruction enum variants ([`ScreenInstruction`],
-/// [`PtyInstruction`], [`ClientInstruction`], etc).
-#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)]
-pub enum ContextType {
- /// A screen-related call.
- Screen(ScreenContext),
- /// A PTY-related call.
- Pty(PtyContext),
- /// A plugin-related call.
- Plugin(PluginContext),
- /// An app-related call.
- Client(ClientContext),
- /// A server-related call.
- IPCServer(ServerContext),
- StdinHandler,
- AsyncTask,
- /// An empty, placeholder call. This should be thought of as representing no call at all.
- /// A call stack representation filled with these is the representation of an empty call stack.
- Empty,
-}
-
-// TODO use the `colored` crate for color formatting
-impl Display for ContextType {
- fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
- let purple = "\u{1b}[1;35m";
- let green = "\u{1b}[0;32m";
- match *self {
- ContextType::Screen(c) => write!(f, "{}screen_thread: {}{:?}", purple, green, c),
- ContextType::Pty(c) => write!(f, "{}pty_thread: {}{:?}", purple, green, c),
- ContextType::Plugin(c) => write!(f, "{}plugin_thread: {}{:?}", purple, green, c),
- ContextType::Client(c) => write!(f, "{}main_thread: {}{:?}", purple, green, c),
- ContextType::IPCServer(c) => write!(f, "{}ipc_server: {}{:?}", purple, green, c),
- ContextType::StdinHandler => {
- write!(f, "{}stdin_handler_thread: {}AcceptInput", purple, green)
- }
- ContextType::AsyncTask => {
- write!(f, "{}stream_terminal_bytes: {}AsyncTask", purple, green)
- }
- ContextType::Empty => write!(f, ""),
- }
- }
-}
-
-// FIXME: Just deriving EnumDiscriminants from strum will remove the need for any of this!!!
-/// Stack call representations corresponding to the different types of [`ScreenInstruction`]s.
-#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
-pub enum ScreenContext {
- HandlePtyBytes,
- Render,
- NewPane,
- HorizontalSplit,
- VerticalSplit,
- WriteCharacter,
- ResizeLeft,
- ResizeRight,
- ResizeDown,
- ResizeUp,
- SwitchFocus,
- FocusNextPane,
- FocusPreviousPane,
- MoveFocusLeft,
- MoveFocusLeftOrPreviousTab,
- MoveFocusDown,
- MoveFocusUp,
- MoveFocusRight,
- MoveFocusRightOrNextTab,
- Exit,
- ScrollUp,
- ScrollDown,
- PageScrollUp,
- PageScrollDown,
- ClearScroll,
- CloseFocusedPane,
- ToggleActiveSyncTab,
- ToggleActiveTerminalFullscreen,
- SetSelectable,
- SetInvisibleBorders,
- SetMaxHeight,
- ClosePane,
- ApplyLayout,
- NewTab,
- SwitchTabNext,
- SwitchTabPrev,
- CloseTab,
- GoToTab,
- UpdateTabName,
- TerminalResize,
- ChangeMode,
-}
-
-// FIXME: Just deriving EnumDiscriminants from strum will remove the need for any of this!!!
-impl From<&ScreenInstruction> for ScreenContext {
- fn from(screen_instruction: &ScreenInstruction) -> Self {
- match *screen_instruction {
- ScreenInstruction::PtyBytes(..) => ScreenContext::HandlePtyBytes,
- ScreenInstruction::Render => ScreenContext::Render,
- ScreenInstruction::NewPane(_) => ScreenContext::NewPane,
- ScreenInstruction::HorizontalSplit(_) => ScreenContext::HorizontalSplit,
- ScreenInstruction::VerticalSplit(_) => ScreenContext::VerticalSplit,
- ScreenInstruction::WriteCharacter(_) => ScreenContext::WriteCharacter,
- ScreenInstruction::ResizeLeft => ScreenContext::ResizeLeft,
- ScreenInstruction::ResizeRight => ScreenContext::ResizeRight,
- ScreenInstruction::ResizeDown => ScreenContext::ResizeDown,
- ScreenInstruction::ResizeUp => ScreenContext::ResizeUp,
- ScreenInstruction::SwitchFocus => ScreenContext::SwitchFocus,
- ScreenInstruction::FocusNextPane => ScreenContext::FocusNextPane,
- ScreenInstruction::FocusPreviousPane => ScreenContext::FocusPreviousPane,
- ScreenInstruction::MoveFocusLeft => ScreenContext::MoveFocusLeft,
- ScreenInstruction::MoveFocusLeftOrPreviousTab => {
- ScreenContext::MoveFocusLeftOrPreviousTab
- }
- ScreenInstruction::MoveFocusDown => ScreenContext::MoveFocusDown,
- ScreenInstruction::MoveFocusUp => ScreenContext::MoveFocusUp,
- ScreenInstruction::MoveFocusRight => ScreenContext::MoveFocusRight,
- ScreenInstruction::MoveFocusRightOrNextTab => ScreenContext::MoveFocusRightOrNextTab,
- ScreenInstruction::Exit => ScreenContext::Exit,
- ScreenInstruction::ScrollUp => ScreenContext::ScrollUp,
- ScreenInstruction::ScrollDown => ScreenContext::ScrollDown,
- ScreenInstruction::PageScrollUp => ScreenContext::PageScrollUp,
- ScreenInstruction::PageScrollDown => ScreenContext::PageScrollDown,
- ScreenInstruction::ClearScroll => ScreenContext::ClearScroll,
- ScreenInstruction::CloseFocusedPane => ScreenContext::CloseFocusedPane,
- ScreenInstruction::ToggleActiveTerminalFullscreen => {
- ScreenContext::ToggleActiveTerminalFullscreen
- }
- ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable,
- ScreenInstruction::SetInvisibleBorders(..) => ScreenContext::SetInvisibleBorders,
- ScreenInstruction::SetMaxHeight(..) => ScreenContext::SetMaxHeight,
- ScreenInstruction::ClosePane(_) => ScreenContext::ClosePane,
- ScreenInstruction::ApplyLayout(..) => ScreenContext::ApplyLayout,
- ScreenInstruction::NewTab(_) => ScreenContext::NewTab,
- ScreenInstruction::SwitchTabNext => ScreenContext::SwitchTabNext,
- ScreenInstruction::SwitchTabPrev => ScreenContext::SwitchTabPrev,
- ScreenInstruction::CloseTab => ScreenContext::CloseTab,
- ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab,
- ScreenInstruction::UpdateTabName(_) => ScreenContext::UpdateTabName,
- ScreenInstruction::TerminalResize(_) => ScreenContext::TerminalResize,
- ScreenInstruction::ChangeMode(_) => ScreenContext::ChangeMode,
- ScreenInstruction::ToggleActiveSyncTab => ScreenContext::ToggleActiveSyncTab,
- }
- }
-}
-
-/// Stack call representations corresponding to the different types of [`PtyInstruction`]s.
-#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
-pub enum PtyContext {
- SpawnTerminal,
- SpawnTerminalVertically,
- SpawnTerminalHorizontally,
- NewTab,
- ClosePane,
- CloseTab,
- Exit,
-}
-
-impl From<&PtyInstruction> for PtyContext {
- fn from(pty_instruction: &PtyInstruction) -> Self {
- match *pty_instruction {
- PtyInstruction::SpawnTerminal(_) => PtyContext::SpawnTerminal,
- PtyInstruction::SpawnTerminalVertically(_) => PtyContext::SpawnTerminalVertically,
- PtyInstruction::SpawnTerminalHorizontally(_) => PtyContext::SpawnTerminalHorizontally,
- PtyInstruction::ClosePane(_) => PtyContext::ClosePane,
- PtyInstruction::CloseTab(_) => PtyContext::CloseTab,
- PtyInstruction::NewTab => PtyContext::NewTab,
- PtyInstruction::Exit => PtyContext::Exit,
- }
- }
-}
-
-// FIXME: This whole pattern *needs* a macro eventually, it's soul-crushing to write
-
-use crate::wasm_vm::PluginInstruction;
-
-/// Stack call representations corresponding to the different types of [`PluginInstruction`]s.
-#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
-pub enum PluginContext {
- Load,
- Update,
- Render,
- Unload,
- Exit,
-}
-
-impl From<&PluginInstruction> for PluginContext {
- fn from(plugin_instruction: &PluginInstruction) -> Self {
- match *plugin_instruction {
- PluginInstruction::Load(..) => PluginContext::Load,
- PluginInstruction::Update(..) => PluginContext::Update,
- PluginInstruction::Render(..) => PluginContext::Render,
- PluginInstruction::Unload(_) => PluginContext::Unload,
- PluginInstruction::Exit => PluginContext::Exit,
- }
- }
-}
-
-/// Stack call representations corresponding to the different types of [`ClientInstruction`]s.
-#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
-pub enum ClientContext {
- Exit,
- Error,
- UnblockInputThread,
- Render,
- ServerError,
-}
-
-impl From<&ClientInstruction> for ClientContext {
- fn from(client_instruction: &ClientInstruction) -> Self {
- match *client_instruction {
- ClientInstruction::Exit => ClientContext::Exit,
- ClientInstruction::Error(_) => ClientContext::Error,
- ClientInstruction::ServerError(_) => ClientContext::ServerError,
- ClientInstruction::Render(_) => ClientContext::Render,
- ClientInstruction::UnblockInputThread => ClientContext::UnblockInputThread,
- }
- }
-}
-
-/// Stack call representations corresponding to the different types of [`ServerInstruction`]s.
-#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
-pub enum ServerContext {
- NewClient,
- Render,
- UnblockInputThread,
- ClientExit,
- Error,
-}
-
-impl From<&ServerInstruction> for ServerContext {
- fn from(server_instruction: &ServerInstruction) -> Self {
- match *server_instruction {
- ServerInstruction::NewClient(..) => ServerContext::NewClient,
- ServerInstruction::Render(_) => ServerContext::Render,
- ServerInstruction::UnblockInputThread => ServerContext::UnblockInputThread,
- ServerInstruction::ClientExit => ServerContext::ClientExit,
- ServerInstruction::Error(_) => ServerContext::Error,
- }
- }
-}