make error model more autonomous
This commit is contained in:
parent
313ac9f414
commit
380d69978c
4 changed files with 40 additions and 47 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
//! Error context system based on a thread-local representation of the call stack, itself based on
|
//! Error context system based on a thread-local representation of the call stack, itself based on
|
||||||
//! the instructions that are sent between threads.
|
//! the instructions that are sent between threads.
|
||||||
|
|
||||||
use super::{AppInstruction, OPENCALLS};
|
use super::{AppInstruction, ASYNCOPENCALLS, OPENCALLS};
|
||||||
use crate::pty_bus::PtyInstruction;
|
use crate::pty_bus::PtyInstruction;
|
||||||
use crate::screen::ScreenInstruction;
|
use crate::screen::ScreenInstruction;
|
||||||
|
|
||||||
|
|
@ -72,6 +72,12 @@ pub fn handle_panic(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
/// A representation of the call stack.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct ErrorContext {
|
pub struct ErrorContext {
|
||||||
|
|
@ -95,7 +101,9 @@ impl ErrorContext {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OPENCALLS.with(|ctx| *ctx.borrow_mut() = *self);
|
ASYNCOPENCALLS
|
||||||
|
.try_with(|ctx| *ctx.borrow_mut() = *self)
|
||||||
|
.unwrap_or_else(|_| OPENCALLS.with(|ctx| *ctx.borrow_mut() = *self));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,6 @@ impl InputHandler {
|
||||||
fn handle_input(&mut self) {
|
fn handle_input(&mut self) {
|
||||||
let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow());
|
let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow());
|
||||||
err_ctx.add_call(ContextType::StdinHandler);
|
err_ctx.add_call(ContextType::StdinHandler);
|
||||||
self.send_pty_instructions.update(err_ctx);
|
|
||||||
self.send_app_instructions.update(err_ctx);
|
|
||||||
self.send_screen_instructions.update(err_ctx);
|
|
||||||
let keybinds = self.config.keybinds.clone();
|
let keybinds = self.config.keybinds.clone();
|
||||||
let alt_left_bracket = vec![27, 91];
|
let alt_left_bracket = vec![27, 91];
|
||||||
loop {
|
loop {
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,13 @@ use crate::cli::CliArgs;
|
||||||
use crate::common::input::config::Config;
|
use crate::common::input::config::Config;
|
||||||
use crate::layout::Layout;
|
use crate::layout::Layout;
|
||||||
use crate::panes::PaneId;
|
use crate::panes::PaneId;
|
||||||
|
use async_std::task_local;
|
||||||
use command_is_executing::CommandIsExecuting;
|
use command_is_executing::CommandIsExecuting;
|
||||||
use directories_next::ProjectDirs;
|
use directories_next::ProjectDirs;
|
||||||
use errors::{AppContext, ContextType, ErrorContext, PluginContext, PtyContext, ScreenContext};
|
use errors::{
|
||||||
|
get_current_ctx, AppContext, ContextType, ErrorContext, PluginContext, PtyContext,
|
||||||
|
ScreenContext,
|
||||||
|
};
|
||||||
use input::handler::input_loop;
|
use input::handler::input_loop;
|
||||||
use os_input_output::OsApi;
|
use os_input_output::OsApi;
|
||||||
use pty_bus::{PtyBus, PtyInstruction};
|
use pty_bus::{PtyBus, PtyInstruction};
|
||||||
|
|
@ -72,32 +76,23 @@ enum SenderType<T: Clone> {
|
||||||
/// synchronously or asynchronously depending on the underlying [`SenderType`].
|
/// synchronously or asynchronously depending on the underlying [`SenderType`].
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SenderWithContext<T: Clone> {
|
pub struct SenderWithContext<T: Clone> {
|
||||||
err_ctx: ErrorContext,
|
|
||||||
sender: SenderType<T>,
|
sender: SenderType<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> SenderWithContext<T> {
|
impl<T: Clone> SenderWithContext<T> {
|
||||||
fn new(err_ctx: ErrorContext, sender: SenderType<T>) -> Self {
|
fn new(sender: SenderType<T>) -> Self {
|
||||||
Self { err_ctx, sender }
|
Self { sender }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends an event, along with the current [`ErrorContext`], on this
|
/// Sends an event, along with the current [`ErrorContext`], on this
|
||||||
/// [`SenderWithContext`]'s channel.
|
/// [`SenderWithContext`]'s channel.
|
||||||
pub fn send(&self, event: T) -> Result<(), mpsc::SendError<(T, ErrorContext)>> {
|
pub fn send(&self, event: T) -> Result<(), mpsc::SendError<(T, ErrorContext)>> {
|
||||||
|
let err_ctx = get_current_ctx();
|
||||||
match self.sender {
|
match self.sender {
|
||||||
SenderType::Sender(ref s) => s.send((event, self.err_ctx)),
|
SenderType::Sender(ref s) => s.send((event, err_ctx)),
|
||||||
SenderType::SyncSender(ref s) => s.send((event, self.err_ctx)),
|
SenderType::SyncSender(ref s) => s.send((event, err_ctx)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates this [`SenderWithContext`]'s [`ErrorContext`]. This is the way one adds
|
|
||||||
/// a call to the error context.
|
|
||||||
///
|
|
||||||
/// Updating [`ErrorContext`]s works in this way so that these contexts are only ever
|
|
||||||
/// allocated on the stack (which is thread-specific), and not on the heap.
|
|
||||||
pub fn update(&mut self, new_ctx: ErrorContext) {
|
|
||||||
self.err_ctx = new_ctx;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: Clone> Send for SenderWithContext<T> {}
|
unsafe impl<T: Clone> Send for SenderWithContext<T> {}
|
||||||
|
|
@ -109,6 +104,12 @@ thread_local!(
|
||||||
static OPENCALLS: RefCell<ErrorContext> = RefCell::default()
|
static OPENCALLS: RefCell<ErrorContext> = RefCell::default()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
task_local! {
|
||||||
|
/// A key to some thread local storage (TLS) that holds a representation of the task's call
|
||||||
|
/// stack in the form of an [`ErrorContext`].
|
||||||
|
static ASYNCOPENCALLS: RefCell<ErrorContext> = RefCell::default()
|
||||||
|
}
|
||||||
|
|
||||||
/// Instructions related to the entire application.
|
/// Instructions related to the entire application.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum AppInstruction {
|
pub enum AppInstruction {
|
||||||
|
|
@ -140,25 +141,23 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
||||||
let (send_screen_instructions, receive_screen_instructions): ChannelWithContext<
|
let (send_screen_instructions, receive_screen_instructions): ChannelWithContext<
|
||||||
ScreenInstruction,
|
ScreenInstruction,
|
||||||
> = mpsc::channel();
|
> = mpsc::channel();
|
||||||
let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow());
|
let send_screen_instructions =
|
||||||
let mut send_screen_instructions =
|
SenderWithContext::new(SenderType::Sender(send_screen_instructions));
|
||||||
SenderWithContext::new(err_ctx, SenderType::Sender(send_screen_instructions));
|
|
||||||
|
|
||||||
let (send_pty_instructions, receive_pty_instructions): ChannelWithContext<PtyInstruction> =
|
let (send_pty_instructions, receive_pty_instructions): ChannelWithContext<PtyInstruction> =
|
||||||
mpsc::channel();
|
mpsc::channel();
|
||||||
let mut send_pty_instructions =
|
let send_pty_instructions = SenderWithContext::new(SenderType::Sender(send_pty_instructions));
|
||||||
SenderWithContext::new(err_ctx, SenderType::Sender(send_pty_instructions));
|
|
||||||
|
|
||||||
let (send_plugin_instructions, receive_plugin_instructions): ChannelWithContext<
|
let (send_plugin_instructions, receive_plugin_instructions): ChannelWithContext<
|
||||||
PluginInstruction,
|
PluginInstruction,
|
||||||
> = mpsc::channel();
|
> = mpsc::channel();
|
||||||
let send_plugin_instructions =
|
let send_plugin_instructions =
|
||||||
SenderWithContext::new(err_ctx, SenderType::Sender(send_plugin_instructions));
|
SenderWithContext::new(SenderType::Sender(send_plugin_instructions));
|
||||||
|
|
||||||
let (send_app_instructions, receive_app_instructions): SyncChannelWithContext<AppInstruction> =
|
let (send_app_instructions, receive_app_instructions): SyncChannelWithContext<AppInstruction> =
|
||||||
mpsc::sync_channel(0);
|
mpsc::sync_channel(0);
|
||||||
let send_app_instructions =
|
let send_app_instructions =
|
||||||
SenderWithContext::new(err_ctx, SenderType::SyncSender(send_app_instructions));
|
SenderWithContext::new(SenderType::SyncSender(send_app_instructions));
|
||||||
|
|
||||||
let mut pty_bus = PtyBus::new(
|
let mut pty_bus = PtyBus::new(
|
||||||
receive_pty_instructions,
|
receive_pty_instructions,
|
||||||
|
|
@ -195,7 +194,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
||||||
.recv()
|
.recv()
|
||||||
.expect("failed to receive event on channel");
|
.expect("failed to receive event on channel");
|
||||||
err_ctx.add_call(ContextType::Pty(PtyContext::from(&event)));
|
err_ctx.add_call(ContextType::Pty(PtyContext::from(&event)));
|
||||||
pty_bus.send_screen_instructions.update(err_ctx);
|
|
||||||
match event {
|
match event {
|
||||||
PtyInstruction::SpawnTerminal(file_to_open) => {
|
PtyInstruction::SpawnTerminal(file_to_open) => {
|
||||||
let pid = pty_bus.spawn_terminal(file_to_open);
|
let pid = pty_bus.spawn_terminal(file_to_open);
|
||||||
|
|
@ -272,8 +270,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
||||||
.recv()
|
.recv()
|
||||||
.expect("failed to receive event on channel");
|
.expect("failed to receive event on channel");
|
||||||
err_ctx.add_call(ContextType::Screen(ScreenContext::from(&event)));
|
err_ctx.add_call(ContextType::Screen(ScreenContext::from(&event)));
|
||||||
screen.send_app_instructions.update(err_ctx);
|
|
||||||
screen.send_pty_instructions.update(err_ctx);
|
|
||||||
match event {
|
match event {
|
||||||
ScreenInstruction::PtyBytes(pid, vte_bytes) => {
|
ScreenInstruction::PtyBytes(pid, vte_bytes) => {
|
||||||
let active_tab = screen.get_active_tab_mut().unwrap();
|
let active_tab = screen.get_active_tab_mut().unwrap();
|
||||||
|
|
@ -433,9 +429,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
||||||
let wasm_thread = thread::Builder::new()
|
let wasm_thread = thread::Builder::new()
|
||||||
.name("wasm".to_string())
|
.name("wasm".to_string())
|
||||||
.spawn({
|
.spawn({
|
||||||
let mut send_pty_instructions = send_pty_instructions.clone();
|
let send_pty_instructions = send_pty_instructions.clone();
|
||||||
let mut send_screen_instructions = send_screen_instructions.clone();
|
let send_screen_instructions = send_screen_instructions.clone();
|
||||||
let mut send_app_instructions = send_app_instructions.clone();
|
let send_app_instructions = send_app_instructions.clone();
|
||||||
|
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let mut plugin_id = 0;
|
let mut plugin_id = 0;
|
||||||
|
|
@ -445,9 +441,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
||||||
.recv()
|
.recv()
|
||||||
.expect("failed to receive event on channel");
|
.expect("failed to receive event on channel");
|
||||||
err_ctx.add_call(ContextType::Plugin(PluginContext::from(&event)));
|
err_ctx.add_call(ContextType::Plugin(PluginContext::from(&event)));
|
||||||
send_screen_instructions.update(err_ctx);
|
|
||||||
send_pty_instructions.update(err_ctx);
|
|
||||||
send_app_instructions.update(err_ctx);
|
|
||||||
match event {
|
match event {
|
||||||
PluginInstruction::Load(pid_tx, path) => {
|
PluginInstruction::Load(pid_tx, path) => {
|
||||||
let project_dirs =
|
let project_dirs =
|
||||||
|
|
@ -556,16 +549,14 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
||||||
.name("ipc_server".to_string())
|
.name("ipc_server".to_string())
|
||||||
.spawn({
|
.spawn({
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
let mut send_pty_instructions = send_pty_instructions.clone();
|
let send_pty_instructions = send_pty_instructions.clone();
|
||||||
let mut send_screen_instructions = send_screen_instructions.clone();
|
let send_screen_instructions = send_screen_instructions.clone();
|
||||||
move || {
|
move || {
|
||||||
std::fs::remove_file(ZELLIJ_IPC_PIPE).ok();
|
std::fs::remove_file(ZELLIJ_IPC_PIPE).ok();
|
||||||
let listener = std::os::unix::net::UnixListener::bind(ZELLIJ_IPC_PIPE)
|
let listener = std::os::unix::net::UnixListener::bind(ZELLIJ_IPC_PIPE)
|
||||||
.expect("could not listen on ipc socket");
|
.expect("could not listen on ipc socket");
|
||||||
let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow());
|
let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow());
|
||||||
err_ctx.add_call(ContextType::IpcServer);
|
err_ctx.add_call(ContextType::IpcServer);
|
||||||
send_pty_instructions.update(err_ctx);
|
|
||||||
send_screen_instructions.update(err_ctx);
|
|
||||||
|
|
||||||
for stream in listener.incoming() {
|
for stream in listener.incoming() {
|
||||||
match stream {
|
match stream {
|
||||||
|
|
@ -637,8 +628,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
||||||
.expect("failed to receive app instruction on channel");
|
.expect("failed to receive app instruction on channel");
|
||||||
|
|
||||||
err_ctx.add_call(ContextType::App(AppContext::from(&app_instruction)));
|
err_ctx.add_call(ContextType::App(AppContext::from(&app_instruction)));
|
||||||
send_screen_instructions.update(err_ctx);
|
|
||||||
send_pty_instructions.update(err_ctx);
|
|
||||||
match app_instruction {
|
match app_instruction {
|
||||||
AppInstruction::Exit => {
|
AppInstruction::Exit => {
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ use ::std::sync::mpsc::Receiver;
|
||||||
use ::std::time::{Duration, Instant};
|
use ::std::time::{Duration, Instant};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use super::{ScreenInstruction, SenderWithContext, OPENCALLS};
|
use super::{ScreenInstruction, SenderWithContext};
|
||||||
use crate::os_input_output::OsApi;
|
use crate::os_input_output::OsApi;
|
||||||
use crate::utils::logging::debug_to_file;
|
use crate::utils::logging::debug_to_file;
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{ContextType, ErrorContext},
|
errors::{get_current_ctx, ContextType, ErrorContext},
|
||||||
panes::PaneId,
|
panes::PaneId,
|
||||||
};
|
};
|
||||||
use crate::{layout::Layout, wasm_vm::PluginInstruction};
|
use crate::{layout::Layout, wasm_vm::PluginInstruction};
|
||||||
|
|
@ -89,15 +89,14 @@ pub struct PtyBus {
|
||||||
|
|
||||||
fn stream_terminal_bytes(
|
fn stream_terminal_bytes(
|
||||||
pid: RawFd,
|
pid: RawFd,
|
||||||
mut send_screen_instructions: SenderWithContext<ScreenInstruction>,
|
send_screen_instructions: SenderWithContext<ScreenInstruction>,
|
||||||
os_input: Box<dyn OsApi>,
|
os_input: Box<dyn OsApi>,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
) -> JoinHandle<()> {
|
) -> JoinHandle<()> {
|
||||||
let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow());
|
let mut err_ctx = get_current_ctx();
|
||||||
task::spawn({
|
task::spawn({
|
||||||
async move {
|
async move {
|
||||||
err_ctx.add_call(ContextType::AsyncTask);
|
err_ctx.add_call(ContextType::AsyncTask);
|
||||||
send_screen_instructions.update(err_ctx);
|
|
||||||
let mut terminal_bytes = ReadFromPid::new(&pid, os_input);
|
let mut terminal_bytes = ReadFromPid::new(&pid, os_input);
|
||||||
|
|
||||||
let mut last_byte_receive_time: Option<Instant> = None;
|
let mut last_byte_receive_time: Option<Instant> = None;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue