108 lines
3.3 KiB
Rust
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();
|
|
}
|