worldwideportal/src/main.rs

108 lines
3.3 KiB
Rust

use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use logging::LoggingEngine;
use parsing::ParsedCommand;
use term_split::TermSplit;
use web_sys::console;
use yew::prelude::*;
pub mod command_handler;
pub mod editor_view;
pub mod frame_view;
pub mod id_intern;
pub mod lineengine;
pub mod logging;
pub mod lua_engine;
pub mod match_table;
pub mod parsing;
pub mod split_panel;
pub mod telnet;
pub mod term_split;
pub mod timer_host;
pub mod websocket;
use crate::editor_view::try_run_script;
use crate::frame_view::*;
use crate::lua_engine::{install_lua_globals, LuaState};
use crate::split_panel::*;
use crate::websocket::RegisteredWebSockets;
#[derive(Properties)]
pub struct GlobalMemoState {
// No strong references allowed between each of these groups of state.
frame_registry: RefCell<RegisteredTermFrames>,
lua_engine: RefCell<LuaState>,
ws_registry: RefCell<RegisteredWebSockets>,
command_queue: RefCell<VecDeque<(FrameId, ParsedCommand)>>,
log_engine: RefCell<LoggingEngine>,
// A cache of the latest layout info (separate from the state).
// Updating this doesn't force a relayout, so only update the cache when
// you also emit a change to the real layout.
layout: RefCell<Rc<GlobalLayoutState>>,
}
type GlobalMemoCell = Rc<GlobalMemoState>;
// Used only for yew. Lua and Frame Registry excluded, as
// changes there should never cause a re-render.
impl PartialEq for GlobalMemoState {
fn eq(&self, _other: &Self) -> bool {
true
}
}
// Used for state that impacts the entire layout. Changes here will
// cause a re-render
#[derive(PartialEq, Properties, Clone)]
pub struct GlobalLayoutState {
term_splits: TermSplit,
frame_views: im::OrdMap<FrameId, FrameViewType>,
}
// Note: Despite interior mutability, you still should always call the
// setter to force a re-render. Interior mutability is used to allow this
// to be baked into the Lua closures and still allow access to the current
// value.
type GlobalLayoutCell = Rc<GlobalLayoutState>;
#[function_component(App)]
fn app() -> Html {
let global_layout: UseStateHandle<GlobalLayoutCell> = use_state(|| {
Rc::new(GlobalLayoutState {
term_splits: TermSplit::Term { frame: FrameId(1) },
frame_views: im::OrdMap::new(),
})
});
let global_memo = use_memo((), |_| GlobalMemoState {
frame_registry: RegisteredTermFrames::new().into(),
ws_registry: RegisteredWebSockets::new().into(),
command_queue: VecDeque::new().into(),
lua_engine: LuaState::setup().expect("Can create interpreter").into(),
layout: RefCell::new((*global_layout).clone()),
log_engine: RefCell::new(Default::default()),
});
use_memo((), |_| {
install_lua_globals(&global_memo, global_layout.setter())
.expect("Couldn't install Lua globals");
match try_run_script("init.lua", &global_memo) {
Ok(_) => {}
Err(e) => {
console::log_1(&format!("Error running init.lua: {}", e).into());
}
}
});
html! {
<div class="toplevel" data-bs-theme="dark">
<TermViewTree global_memo={global_memo.clone()}
global_layout={global_layout.clone()}/>
</div>
}
}
fn main() {
console_error_panic_hook::set_once();
yew::Renderer::<App>::new().render();
}