From 4585db043321c141cdcd14eaf04f874b6111420b Mon Sep 17 00:00:00 2001 From: Condorra Date: Sat, 5 Oct 2024 19:28:39 +1000 Subject: [PATCH] Get editor showing (not yet usable) on #editor --- index.html | 40 ++++++ package-lock.json | 184 +++++++++++++++++++++++++++- package.json | 7 +- src/command_handler.rs | 6 +- src/editor_view.rs | 164 +++++++++++++++++++++++++ src/{term_view.rs => frame_view.rs} | 70 +++++++---- src/logging.rs | 24 ++-- src/lua_engine.rs | 13 +- src/lua_engine/frameroutes.rs | 6 +- src/lua_engine/frames.rs | 66 +++++++--- src/lua_engine/muds.rs | 6 +- src/main.rs | 17 +-- src/term_split.rs | 139 +++++---------------- src/timer_host.rs | 6 +- styles.css | 6 + 15 files changed, 568 insertions(+), 186 deletions(-) create mode 100644 src/editor_view.rs rename src/{term_view.rs => frame_view.rs} (81%) diff --git a/index.html b/index.html index 153ca41..ea095c5 100644 --- a/index.html +++ b/index.html @@ -1,11 +1,51 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/package-lock.json b/package-lock.json index cb470fc..6f03422 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,128 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@codemirror/legacy-modes": "^6.4.1", + "@codemirror/state": "^6.4.1", "@xterm/addon-fit": "^0.10.0", - "@xterm/xterm": "^5.5.0" + "@xterm/xterm": "^5.5.0", + "bootstrap": "^5.3.3", + "bootstrap-icons": "^1.11.3", + "codemirror": "^6.0.1" + } + }, + "node_modules/@codemirror/autocomplete": { + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.1.tgz", + "integrity": "sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + }, + "peerDependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.6.2.tgz", + "integrity": "sha512-Fq7eWOl1Rcbrfn6jD8FPCj9Auaxdm5nIK5RYOeW7ughnd/rY5AmPg6b+CfsG39ZHdwiwe8lde3q8uR7CF5S0yQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.27.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.3.tgz", + "integrity": "sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.1.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/legacy-modes": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.4.1.tgz", + "integrity": "sha512-vdg3XY7OAs5uLDx2Iw+cGfnwtd7kM+Et/eMsqAGTfT/JKiVBQZXosTzjEbWAi/FrY6DcQIz8mQjBozFHZEUWQA==", + "dependencies": { + "@codemirror/language": "^6.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.2.tgz", + "integrity": "sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.5.6", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.6.tgz", + "integrity": "sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz", + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==" + }, + "node_modules/@codemirror/view": { + "version": "6.34.1", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.34.1.tgz", + "integrity": "sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==", + "dependencies": { + "@codemirror/state": "^6.4.0", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@lezer/common": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.2.tgz", + "integrity": "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw==" + }, + "node_modules/@lezer/highlight": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz", + "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", + "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" } }, "node_modules/@xterm/addon-fit": { @@ -25,6 +145,68 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==" + }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/bootstrap-icons": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.3.tgz", + "integrity": "sha512-+3lpHrCw/it2/7lBL15VR0HEumaBss0+f/Lb6ZvHISn1mlK83jjFpooTLsMWbIjJMDjDjOExMsTxnXSIT4k4ww==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ] + }, + "node_modules/codemirror": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", + "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==" + }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==" + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==" } } } diff --git a/package.json b/package.json index 6c022a0..4f401c1 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,12 @@ "author": "", "license": "ISC", "dependencies": { + "@codemirror/legacy-modes": "^6.4.1", + "@codemirror/state": "^6.4.1", "@xterm/addon-fit": "^0.10.0", - "@xterm/xterm": "^5.5.0" + "@xterm/xterm": "^5.5.0", + "bootstrap": "^5.3.3", + "bootstrap-icons": "^1.11.3", + "codemirror": "^6.0.1" } } diff --git a/src/command_handler.rs b/src/command_handler.rs index 60fea0d..9ac7246 100644 --- a/src/command_handler.rs +++ b/src/command_handler.rs @@ -2,7 +2,7 @@ use crate::{ echo_to_term_frame, lua_engine::LuaState, parsing::{parse_commands, ParsedCommand}, - GlobalMemoCell, TermFrame, + FrameId, GlobalMemoCell, }; use itertools::Itertools; use wasm_bindgen::JsValue; @@ -20,7 +20,7 @@ pub fn debrace(inp: &str) -> &str { fn reentrant_command_handler( lua_state: &mut LuaState, globals: &GlobalMemoCell, - term_frame: &TermFrame, + term_frame: &FrameId, commands_in: &[ParsedCommand], ) { lua_state.set_current_frame(term_frame); @@ -68,7 +68,7 @@ fn reentrant_command_handler( } } -pub fn command_handler(globals: &GlobalMemoCell, term_frame: &TermFrame, command_in: &str) { +pub fn command_handler(globals: &GlobalMemoCell, term_frame: &FrameId, command_in: &str) { echo_to_term_frame(globals, term_frame, "\r").unwrap_or(()); { let mut cq = globals.command_queue.borrow_mut(); diff --git a/src/editor_view.rs b/src/editor_view.rs new file mode 100644 index 0000000..875eb82 --- /dev/null +++ b/src/editor_view.rs @@ -0,0 +1,164 @@ +use std::{ops::Deref, rc::Rc}; + +use anyhow::Error; +use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; +use web_sys::{window, Node}; +use yew::{ + function_component, html, use_effect_with, use_node_ref, use_state_eq, AttrValue, Callback, + Html, Properties, UseStateHandle, +}; + +use crate::{FrameId, GlobalLayoutState, GlobalMemoCell, PanelDirection, SplitPanel}; + +#[derive(Properties, PartialEq, Clone)] +pub struct EditorViewProps { + pub frame: FrameId, + pub global_memo: GlobalMemoCell, + pub global_layout: UseStateHandle>, +} + +fn close_editor(frame: &FrameId, global_layout: &UseStateHandle>) { + let mut gl_new: GlobalLayoutState = global_layout.as_ref().clone(); + gl_new.frame_views.remove(frame); + global_layout.set(gl_new.into()); +} + +#[derive(PartialEq, Clone)] +pub struct EditorState { + error_msg: Option, + available_files: Vec, +} + +fn fetch_initial_editor_state_or_fail() -> anyhow::Result { + let win = window().ok_or_else(|| Error::msg("Can't get window"))?; + win.local_storage() + .map_err(|_| Error::msg("Error retrieving localStorage"))? + .ok_or_else(|| Error::msg("Local storage not available"))?; + Ok(EditorState { + error_msg: None, + available_files: vec![], + }) +} + +fn fetch_initial_editor_state() -> EditorState { + match fetch_initial_editor_state_or_fail() { + Ok(s) => s, + Err(e) => EditorState { + error_msg: Some(format!("Can't load editor data: {}", e.to_string()).into()), + available_files: vec![], + }, + } +} + +#[function_component(EditorNav)] +fn editor_nav(props: &EditorViewProps) -> Html { + let global_layout = props.global_layout.clone(); + let frame = props.frame.clone(); + html! { +
+ +
+ } +} + +#[wasm_bindgen(getter_with_clone)] +struct EditorViewConfig { + pub doc: String, + pub extensions: Vec, + pub parent: Node, +} + +#[wasm_bindgen(module = codemirror)] +extern "C" { + type EditorView; + #[derive(Clone)] + type CMExtension; + + #[wasm_bindgen(constructor)] + fn new(settings: EditorViewConfig) -> EditorView; + + #[wasm_bindgen(js_name = basicSetup, thread_local)] + static BASIC_SETUP: CMExtension; +} + +#[wasm_bindgen(module = "@codemirror/legacy-modes/mode/lua")] +extern "C" { + #[wasm_bindgen(js_name = lua, thread_local)] + static LUA: StreamLanguage; +} + +#[wasm_bindgen(module = "@codemirror/language")] +extern "C" { + #[derive(Clone)] + type StreamLanguage; + + #[wasm_bindgen(js_namespace = StreamLanguage, js_name = define)] + fn streamlanguage_define(input: StreamLanguage) -> CMExtension; +} + +#[function_component(EditorArea)] +fn editor_area(props: &EditorViewProps) -> Html { + let node_ref = use_node_ref(); + use_effect_with(node_ref.clone(), |node_ref| match node_ref.get() { + None => {} + Some(node) => { + EditorView::new(EditorViewConfig { + doc: "Hello World".to_owned(), + extensions: vec![ + BASIC_SETUP.with(CMExtension::clone), + StreamLanguage::streamlanguage_define(LUA.with(StreamLanguage::clone)), + ], + parent: node, + }); + } + }); + html! { +
+
+ } +} + +#[derive(Properties, PartialEq, Clone)] +pub struct ErrorBarProps { + pub msg: AttrValue, + pub dismiss: Callback<()>, +} + +#[function_component(ErrorBar)] +fn error_bar(props: &ErrorBarProps) -> Html { + let props = props.clone(); + html! { + + } +} + +#[function_component(CodeEditorView)] +pub fn editor_view(props: &EditorViewProps) -> Html { + let editor_state: UseStateHandle = use_state_eq(fetch_initial_editor_state); + + html! { + <> + {match editor_state.error_msg.as_ref() { + None => { html! { <> }} + Some(msg) => html! { + } + }} + }} + second={html!{}} + /> + + } +} diff --git a/src/term_view.rs b/src/frame_view.rs similarity index 81% rename from src/term_view.rs rename to src/frame_view.rs index d1fda86..55cd308 100644 --- a/src/term_view.rs +++ b/src/frame_view.rs @@ -7,6 +7,7 @@ use yew::prelude::*; use crate::{ command_handler::command_handler, + editor_view::CodeEditorView, lineengine::line::{Readline, ReadlineEvent}, term_split::TermSplit, timer_host::TimerHost, @@ -69,11 +70,17 @@ extern "C" { #[derive(Eq, Ord, Hash, PartialEq, PartialOrd, Clone, Debug, Collect)] #[collect(require_static)] -pub struct TermFrame(pub u64); +pub struct FrameId(pub u64); + +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)] +pub enum FrameViewType { + Terminal, + Editor, +} #[derive(Properties)] -pub struct TermFrameData { - pub id: TermFrame, +pub struct FrameData { + pub id: FrameId, pub term: Terminal, pub fit: FitAddon, pub node: Node, @@ -86,21 +93,21 @@ pub struct TermFrameData { )>, } -impl PartialEq for TermFrameData { +impl PartialEq for FrameData { fn eq(&self, other: &Self) -> bool { // Only the ID matters, the rest are just reference data. self.id == other.id } } -pub type RegisteredTermFrames = HashMap; +pub type RegisteredTermFrames = HashMap; fn get_or_make_term_frame<'a>( - frame: &TermFrame, + frame: &FrameId, frames: &'a mut RegisteredTermFrames, // Only used for callbacks, expected frames already borrowed mut! globals: &GlobalMemoCell, -) -> &'a TermFrameData { +) -> &'a mut FrameData { frames.entry(frame.clone()).or_insert_with(|| { let term = Terminal::new(); let fit = FitAddon::new(); @@ -124,7 +131,7 @@ fn get_or_make_term_frame<'a>( fit.fit(); let term_for_readline: Terminal = Terminal { obj: term.clone() }; let initial_size = (term.cols(), term.rows()); - let mut new_data: TermFrameData = TermFrameData { + let mut new_data: FrameData = FrameData { id: frame.clone(), term: Terminal { obj: term.clone() }, fit, @@ -142,7 +149,7 @@ fn get_or_make_term_frame<'a>( retained_closures: None, }; - let frame_for_resize: TermFrame = frame.clone(); + let frame_for_resize: FrameId = frame.clone(); let globals_for_resize: GlobalMemoCell = globals.clone(); let resize_closure = Closure::new(move |dims: Dims| { globals_for_resize @@ -161,7 +168,7 @@ fn get_or_make_term_frame<'a>( }); term.onResize(&resize_closure); - let frame_for_ondata: TermFrame = frame.clone(); + let frame_for_ondata: FrameId = frame.clone(); let globals_for_ondata: GlobalMemoCell = globals.clone(); let data_closure = Closure::new(move |d: String| { let new_lines: Vec = match globals_for_ondata @@ -200,8 +207,9 @@ fn get_or_make_term_frame<'a>( #[derive(Properties, PartialEq)] pub struct TermViewProps { - pub terminal: TermFrame, + pub terminal: FrameId, pub global_memo: GlobalMemoCell, + pub global_layout: UseStateHandle, } #[function_component(TermView)] @@ -209,8 +217,20 @@ pub fn term_view(props: &TermViewProps) -> Html { let mut frame_reg = props.global_memo.frame_registry.borrow_mut(); let term = get_or_make_term_frame(&props.terminal, &mut frame_reg, &props.global_memo); term.fit.fit(); - html! { - {Html::VRef(term.node.clone())} + match props + .global_layout + .frame_views + .get(&props.terminal) + .cloned() + .unwrap_or(FrameViewType::Terminal) + { + FrameViewType::Terminal => Html::VRef(term.node.clone()), + FrameViewType::Editor => html! { + + }, } } @@ -222,35 +242,43 @@ pub struct TermViewTreeProps { #[function_component(TermViewTree)] pub fn term_view_tree(props: &TermViewTreeProps) -> Html { - fn mk_term_view_tree(global: &GlobalMemoCell, split: &TermSplit) -> Html { + fn mk_term_view_tree( + global: &GlobalMemoCell, + layout: UseStateHandle, + split: &TermSplit, + ) -> Html { use TermSplit::*; match split { Term { frame } => html! { - + }, Horizontal { left, right } => html! { }, Vertical { top, bottom } => html! { }, } } - mk_term_view_tree(&props.global_memo, &props.global_layout.term_splits) + mk_term_view_tree( + &props.global_memo, + props.global_layout.clone(), + &props.global_layout.term_splits, + ) } pub fn echo_to_term_frame( global: &GlobalMemoCell, - frame_id: &TermFrame, + frame_id: &FrameId, message: &str, ) -> Result<(), &'static str> { global diff --git a/src/logging.rs b/src/logging.rs index fb4c987..6c54076 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -22,19 +22,19 @@ use web_sys::{ IdbTransactionMode, Url, }; -use crate::{echo_to_term_frame, GlobalMemoCell, TermFrame}; +use crate::{echo_to_term_frame, FrameId, GlobalMemoCell}; #[derive(Clone, Debug)] pub enum QueuedAction { LogEvent(LogEvent), - ReportOnLogStreams(TermFrame), + ReportOnLogStreams(FrameId), DeleteLogs(DeleteLogs), DownloadLogs(DownloadLogs), } #[derive(Clone, Debug)] pub struct DeleteLogs { - pub reply_to: TermFrame, + pub reply_to: FrameId, pub stream: String, pub min_date: String, pub max_date: String, @@ -42,7 +42,7 @@ pub struct DeleteLogs { #[derive(Clone, Debug)] pub struct DownloadLogs { - pub reply_to: TermFrame, + pub reply_to: FrameId, pub stream: String, pub min_date: String, pub max_date: String, @@ -114,7 +114,7 @@ async fn async_init_logging() -> Result { Ok(LoggingEngine::Ready { db: db.into() }) } -fn logging_broken_message(global: &GlobalMemoCell, frame: &TermFrame) { +fn logging_broken_message(global: &GlobalMemoCell, frame: &FrameId) { let _ = echo_to_term_frame(global, frame, "Couldn't enable logging. This sometimes happens if your browser doesn't enable indexed storage, or is in a mode (e.g. private browsing) where such storage is not permitted.\r\n"); } @@ -143,7 +143,7 @@ fn init_logging(global: &GlobalMemoCell) { } Err(_) => { if let LoggingEngine::Initialising { .. } = global.log_engine.borrow().deref() { - logging_broken_message(&global, &TermFrame(1)); + logging_broken_message(&global, &FrameId(1)); } } } @@ -181,7 +181,7 @@ fn queue_immediate_log(global: &GlobalMemoCell, event: LogEvent) { async fn immediate_report_log_frame_refutable( global: GlobalMemoCell, db: &IdbDatabase, - frame: TermFrame, + frame: FrameId, ) -> Result<(), DomException> { let trans = db.transaction_on_one("logs")?; let store = trans.object_store("logs")?; @@ -216,7 +216,7 @@ async fn immediate_report_log_frame_refutable( async fn immediate_report_log_frame_async( global: GlobalMemoCell, db: Arc, - frame: TermFrame, + frame: FrameId, ) { match immediate_report_log_frame_refutable(global, &db, frame).await { Ok(()) => {} @@ -229,7 +229,7 @@ async fn immediate_report_log_frame_async( } } -fn immediate_report_log_frame(global: &GlobalMemoCell, frame: TermFrame) { +fn immediate_report_log_frame(global: &GlobalMemoCell, frame: FrameId) { let log_engine = global.log_engine.borrow(); if let LoggingEngine::Ready { db } = log_engine.deref() { spawn_local(immediate_report_log_frame_async( @@ -450,7 +450,7 @@ pub fn log(global: &GlobalMemoCell, event: &LogEvent) { } } -pub fn start_listing_logs(global: &GlobalMemoCell, send_to: &TermFrame) { +pub fn start_listing_logs(global: &GlobalMemoCell, send_to: &FrameId) { let mut engine_borrow = global.log_engine.borrow_mut(); match engine_borrow.deref_mut() { LoggingEngine::Uninitialised => { @@ -475,7 +475,7 @@ pub fn start_listing_logs(global: &GlobalMemoCell, send_to: &TermFrame) { pub fn start_deleting_logs( global: &GlobalMemoCell, - reply_to: &TermFrame, + reply_to: &FrameId, stream: &str, min_date: &str, max_date: &str, @@ -510,7 +510,7 @@ pub fn start_deleting_logs( pub fn start_downloading_logs( global: &GlobalMemoCell, - reply_to: &TermFrame, + reply_to: &FrameId, stream: &str, min_date: &str, max_date: &str, diff --git a/src/lua_engine.rs b/src/lua_engine.rs index 8921975..ee12135 100644 --- a/src/lua_engine.rs +++ b/src/lua_engine.rs @@ -17,7 +17,7 @@ use crate::{ match_table_try_run_sub, }, parsing::ParsedCommand, - GlobalLayoutCell, GlobalMemoCell, TermFrame, + FrameId, GlobalLayoutCell, GlobalMemoCell, }; pub struct LuaState { @@ -38,19 +38,19 @@ impl LuaState { Ok(LuaState { interp, exec }) } - fn try_set_current_frame(&mut self, frame: &TermFrame) -> Result<(), ExternError> { + fn try_set_current_frame(&mut self, frame: &FrameId) -> Result<(), ExternError> { self.interp.try_enter(|ctx| { let info_table = Table::from_value(ctx, ctx.get_global("info")?)?; info_table.set( ctx, ctx.intern_static(b"current_frame"), - intern_id::(ctx, frame.clone()), + intern_id::(ctx, frame.clone()), )?; Ok(()) }) } - pub fn set_current_frame(&mut self, frame: &TermFrame) { + pub fn set_current_frame(&mut self, frame: &FrameId) { // We silently ignore errors here. Failure can happen if the Lua code does weird things // like messes with the info global, so better to just ignore. self.try_set_current_frame(frame).unwrap_or(()) @@ -104,7 +104,7 @@ impl LuaState { pub(crate) fn dispatch_normal_command( &mut self, - frame: &TermFrame, + frame: &FrameId, command: &str, ) -> anyhow::Result<()> { self.interp.try_enter(|ctx| { @@ -187,6 +187,7 @@ pub fn install_lua_globals( register_command!(echo); register_command!(echo_frame); register_command!(echo_frame_raw); + register_command!(editor); register_command!(hsplit); register_command!(cmd_list_logs, "listlogs"); register_command!(mud_log, "log"); @@ -341,7 +342,7 @@ fn lua_global_initialisation(global_memo: &GlobalMemoCell) -> Result<(), String> lua_engine_ref.interp.enter(|ctx| { ctx.fetch(&lua_engine_ref.exec).restart( ctx, - Function::Callback(ensure_frame_instance(ctx, &TermFrame(1))), + Function::Callback(ensure_frame_instance(ctx, &FrameId(1))), (), ); }); diff --git a/src/lua_engine/frameroutes.rs b/src/lua_engine/frameroutes.rs index e95e5e6..2c3ad48 100644 --- a/src/lua_engine/frameroutes.rs +++ b/src/lua_engine/frameroutes.rs @@ -1,6 +1,6 @@ use piccolo::{Callback, CallbackReturn, Context, FromValue, Table}; -use crate::{echo_to_term_frame, id_intern::intern_id, GlobalMemoCell, TermFrame}; +use crate::{echo_to_term_frame, id_intern::intern_id, FrameId, GlobalMemoCell}; use super::try_unwrap_frame; @@ -15,7 +15,7 @@ pub(super) fn new_frameroute<'gc>( .pop_front() .ok_or_else(|| anyhow::Error::msg("classes.frameroute:new missing object!"))?, )?; - let frame: TermFrame = try_unwrap_frame( + let frame: FrameId = try_unwrap_frame( ctx, &stack .pop_front() @@ -48,7 +48,7 @@ pub(super) fn frameroute_route<'gc>( .pop_front() .ok_or_else(|| anyhow::Error::msg("frameroute:route called without line!"))?, )?; - let frame: TermFrame = + let frame: FrameId = try_unwrap_frame(ctx, &frameroute.get(ctx, ctx.intern_static(b"frame"))?)?; // We ignore errors with the term frame to avoid breaking the entire client for one closed frame. diff --git a/src/lua_engine/frames.rs b/src/lua_engine/frames.rs index 2b78dc1..788b24e 100644 --- a/src/lua_engine/frames.rs +++ b/src/lua_engine/frames.rs @@ -3,7 +3,7 @@ use crate::{ id_intern::intern_id, match_table::{create_match_table, match_table_add, match_table_remove}, timer_host::TimerHostAccessContext, - GlobalLayoutCell, GlobalLayoutState, GlobalMemoCell, TermFrame, + FrameId, FrameViewType, GlobalLayoutCell, GlobalLayoutState, GlobalMemoCell, }; use gc_arena::{Gc, Rootable}; use itertools::Itertools; @@ -19,7 +19,7 @@ use super::call_checking_metatable; pub fn alias(ctx: Context<'_>) -> Callback<'_> { Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { let info: Table = ctx.get_global("info")?; - let cur_frame_id: TermFrame = + let cur_frame_id: FrameId = try_unwrap_frame(ctx, &info.get(ctx, ctx.intern_static(b"current_frame"))?)?; let frames: Table = ctx.get_global("frames")?; let cur_frame: Table = frames.get(ctx, cur_frame_id.0 as i64)?; @@ -65,7 +65,7 @@ pub fn alias(ctx: Context<'_>) -> Callback<'_> { pub fn unalias(ctx: Context<'_>) -> Callback<'_> { Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { let info: Table = ctx.get_global("info")?; - let cur_frame_id: TermFrame = + let cur_frame_id: FrameId = try_unwrap_frame(ctx, &info.get(ctx, ctx.intern_static(b"current_frame"))?)?; let frames: Table = ctx.get_global("frames")?; let cur_frame: Table = frames.get(ctx, cur_frame_id.0 as i64)?; @@ -98,7 +98,7 @@ pub fn unalias(ctx: Context<'_>) -> Callback<'_> { } pub fn list_match_tab<'gc>( - frame: TermFrame, + frame: FrameId, aliases: UserData<'gc>, ctx: Context<'gc>, ) -> Result, Error<'gc>> { @@ -147,7 +147,7 @@ pub fn echo_frame_raw<'gc, 'a>( ) -> Callback<'gc> { let global_memo = global_memo.clone(); Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { - let frame: TermFrame = try_unwrap_frame( + let frame: FrameId = try_unwrap_frame( ctx, &stack .pop_front() @@ -214,7 +214,7 @@ pub fn vsplit<'gc>( let global_memo = global_memo.clone(); Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { let path: String = stack.from_front(ctx)?; - let frame: TermFrame = TermFrame(stack.from_front(ctx)?); + let frame: FrameId = FrameId(stack.from_front(ctx)?); let new_splits = global_memo .layout .borrow() @@ -223,6 +223,7 @@ pub fn vsplit<'gc>( .map_err(|e| e.into_value(ctx))?; let new_layout = Rc::new(GlobalLayoutState { term_splits: new_splits.clone(), + ..(*(global_memo.layout.borrow().as_ref())).clone() }); global_layout.set(new_layout.clone()); *(global_memo.layout.borrow_mut()) = new_layout; @@ -242,7 +243,7 @@ pub fn hsplit<'gc>( let global_memo = global_memo.clone(); Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { let path: String = stack.from_front(ctx)?; - let frame: TermFrame = TermFrame(stack.from_front(ctx)?); + let frame: FrameId = FrameId(stack.from_front(ctx)?); let new_splits = global_memo .layout .borrow() @@ -251,6 +252,7 @@ pub fn hsplit<'gc>( .map_err(|e| e.into_value(ctx))?; let new_layout = Rc::new(GlobalLayoutState { term_splits: new_splits.clone(), + ..(*(global_memo.layout.borrow().as_ref())).clone() }); global_layout.set(new_layout.clone()); *(global_memo.layout.borrow_mut()) = new_layout; @@ -278,6 +280,7 @@ pub fn panel_merge<'gc>( .map_err(|e| e.into_value(ctx))?; let new_layout = Rc::new(GlobalLayoutState { term_splits: new_splits.clone(), + ..(*(global_memo.layout.borrow().as_ref())).clone() }); global_layout.set(new_layout.clone()); *(global_memo.layout.borrow_mut()) = new_layout; @@ -288,17 +291,17 @@ pub fn panel_merge<'gc>( pub fn try_unwrap_frame<'gc>( ctx: Context<'gc>, value: &Value<'gc>, -) -> Result> { +) -> Result> { match u64::from_value(ctx, *value) { - Ok(v) => Ok(TermFrame(v)), + Ok(v) => Ok(FrameId(v)), Err(_) => Ok(UserData::from_value(ctx, *value)? - .downcast:: Gc<'gcb, TermFrame>]>()? + .downcast:: Gc<'gcb, FrameId>]>()? .as_ref() .clone()), } } -pub fn ensure_frame_instance<'gc>(ctx: Context<'gc>, frame: &TermFrame) -> Callback<'gc> { +pub fn ensure_frame_instance<'gc>(ctx: Context<'gc>, frame: &FrameId) -> Callback<'gc> { let frame = frame.clone(); Callback::from_fn(&ctx, move |ctx, _ex, _stack| { let frames: Table = ctx.get_global("frames")?; @@ -313,7 +316,7 @@ pub fn ensure_frame_instance<'gc>(ctx: Context<'gc>, frame: &TermFrame) -> Callb frames.set(ctx, frame.0 as i64, frame_tab)?; // Call frame_tab:new(frame) to setup. - let frame = intern_id::(ctx, frame.clone()); + let frame = intern_id::(ctx, frame.clone()); let seq = async_sequence(&ctx, move |locals, mut seq| { let frame_tab = locals.stash(&ctx, frame_tab); let frame = locals.stash(&ctx, frame); @@ -444,7 +447,7 @@ pub(super) fn frame_input<'gc>(ctx: Context<'gc>, _global_memo: &GlobalMemoCell) fn list_timers<'gc>( ctx: Context<'gc>, global_memo: &GlobalMemoCell, - cur_frame_id: TermFrame, + cur_frame_id: FrameId, ) -> Result<(), Error<'gc>> { let timer_val = match global_memo.frame_registry.borrow().get(&cur_frame_id) { None => Err(anyhow::Error::msg("Frame no longer exists"))?, @@ -486,7 +489,7 @@ fn list_timers<'gc>( struct GlobalCellTermFrameTimerHostAccess { global_memo: GlobalMemoCell, - frame: TermFrame, + frame: FrameId, } impl TimerHostAccessContext for GlobalCellTermFrameTimerHostAccess { fn with_ref(&self, f: F) @@ -512,7 +515,7 @@ pub(super) fn tick<'gc>( let global_memo = global_memo.clone(); Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { let info: Table = ctx.get_global("info")?; - let cur_frame_id: TermFrame = + let cur_frame_id: FrameId = try_unwrap_frame(ctx, &info.get(ctx, ctx.intern_static(b"current_frame"))?)?; if stack.is_empty() { @@ -586,7 +589,7 @@ pub(super) fn delay<'gc>( let global_memo = global_memo.clone(); Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { let info: Table = ctx.get_global("info")?; - let cur_frame_id: TermFrame = + let cur_frame_id: FrameId = try_unwrap_frame(ctx, &info.get(ctx, ctx.intern_static(b"current_frame"))?)?; if stack.is_empty() { @@ -660,7 +663,7 @@ pub(super) fn untick<'gc>( let global_memo = global_memo.clone(); Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { let info: Table = ctx.get_global("info")?; - let cur_frame_id: TermFrame = + let cur_frame_id: FrameId = try_unwrap_frame(ctx, &info.get(ctx, ctx.intern_static(b"current_frame"))?)?; let name = stack.consume::(ctx)?.to_str()?.to_owned(); @@ -675,3 +678,32 @@ pub(super) fn untick<'gc>( Ok(piccolo::CallbackReturn::Return) }) } + +pub(super) fn editor<'gc>( + ctx: Context<'gc>, + global_memo: &GlobalMemoCell, + global_layout: &UseStateSetter, +) -> Callback<'gc> { + let global_memo = global_memo.clone(); + let global_layout = global_layout.clone(); + Callback::from_fn(&ctx, move |ctx, _ex, _stack| { + let info: Table = ctx.get_global("info")?; + let cur_frame_id: FrameId = + try_unwrap_frame(ctx, &info.get(ctx, ctx.intern_static(b"current_frame"))?)?; + match global_memo + .frame_registry + .borrow_mut() + .get_mut(&cur_frame_id) + { + None => Err(anyhow::Error::msg("Frame no longer exists"))?, + Some(_frame_dat) => { + let mut new_gl: GlobalLayoutState = (*global_memo.layout.borrow().as_ref()).clone(); + new_gl + .frame_views + .insert(cur_frame_id, FrameViewType::Editor); + global_layout.set(new_gl.into()); + } + }; + Ok(piccolo::CallbackReturn::Return) + }) +} diff --git a/src/lua_engine/muds.rs b/src/lua_engine/muds.rs index 5a6a47b..e6950ed 100644 --- a/src/lua_engine/muds.rs +++ b/src/lua_engine/muds.rs @@ -15,7 +15,7 @@ use crate::{ match_table::{create_match_table, match_table_add, match_table_remove}, telnet::{parse_telnet_buf, TelnetOutput}, websocket::{connect_websocket, send_message_to_mud, WebSocketId}, - GlobalLayoutCell, GlobalMemoCell, TermFrame, + FrameId, GlobalLayoutCell, GlobalMemoCell, }; use super::{call_checking_metatable, list_match_tab, try_unwrap_frame, LuaState}; @@ -537,7 +537,7 @@ pub(super) fn new_mud<'gc>(ctx: Context<'gc>) -> Callback<'gc> { pub(super) fn mud_trigger<'gc>(ctx: Context<'gc>) -> Callback<'gc> { Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { let info: Table = ctx.get_global("info")?; - let cur_frame_id: TermFrame = + let cur_frame_id: FrameId = try_unwrap_frame(ctx, &info.get(ctx, ctx.intern_static(b"current_frame"))?)?; let frames: Table = ctx.get_global("frames")?; let cur_frame: Table = frames.get(ctx, cur_frame_id.0 as i64)?; @@ -592,7 +592,7 @@ pub(super) fn mud_trigger<'gc>(ctx: Context<'gc>) -> Callback<'gc> { pub(super) fn mud_untrigger(ctx: Context<'_>) -> Callback<'_> { Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { let info: Table = ctx.get_global("info")?; - let cur_frame_id: TermFrame = + let cur_frame_id: FrameId = try_unwrap_frame(ctx, &info.get(ctx, ctx.intern_static(b"current_frame"))?)?; let frames: Table = ctx.get_global("frames")?; let cur_frame: Table = frames.get(ctx, cur_frame_id.0 as i64)?; diff --git a/src/main.rs b/src/main.rs index f942b33..65866e5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,8 @@ use term_split::TermSplit; 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; @@ -17,12 +19,11 @@ pub mod parsing; pub mod split_panel; pub mod telnet; pub mod term_split; -pub mod term_view; pub mod timer_host; pub mod websocket; +use crate::frame_view::*; use crate::lua_engine::{install_lua_globals, LuaState}; use crate::split_panel::*; -use crate::term_view::*; use crate::websocket::RegisteredWebSockets; #[derive(Properties)] @@ -31,7 +32,7 @@ pub struct GlobalMemoState { frame_registry: RefCell, lua_engine: RefCell, ws_registry: RefCell, - command_queue: RefCell>, + command_queue: RefCell>, log_engine: RefCell, // A cache of the latest layout info (separate from the state). @@ -51,9 +52,10 @@ impl PartialEq for GlobalMemoState { // Used for state that impacts the entire layout. Changes here will // cause a re-render -#[derive(PartialEq, Properties)] +#[derive(PartialEq, Properties, Clone)] pub struct GlobalLayoutState { term_splits: TermSplit, + frame_views: im::OrdMap, } // Note: Despite interior mutability, you still should always call the // setter to force a re-render. Interior mutability is used to allow this @@ -65,9 +67,8 @@ type GlobalLayoutCell = Rc; fn app() -> Html { let global_layout: UseStateHandle = use_state(|| { Rc::new(GlobalLayoutState { - term_splits: TermSplit::Term { - frame: TermFrame(1), - }, + term_splits: TermSplit::Term { frame: FrameId(1) }, + frame_views: im::OrdMap::new(), }) }); let global_memo = use_memo((), |_| GlobalMemoState { @@ -84,7 +85,7 @@ fn app() -> Html { }); html! { -
+
diff --git a/src/term_split.rs b/src/term_split.rs index 59abf58..3d1827d 100644 --- a/src/term_split.rs +++ b/src/term_split.rs @@ -1,12 +1,12 @@ use itertools::Itertools; use std::{collections::BTreeMap, rc::Rc}; -use crate::TermFrame; +use crate::FrameId; #[derive(PartialEq, Eq, Debug, Clone)] pub enum TermSplit { Term { - frame: TermFrame, + frame: FrameId, }, Horizontal { left: Rc, @@ -19,7 +19,7 @@ pub enum TermSplit { } impl TermSplit { - fn collect_term_frames(&self, into: &mut BTreeMap) { + fn collect_term_frames(&self, into: &mut BTreeMap) { match self { TermSplit::Term { frame } => { into.entry(frame.clone()) @@ -38,7 +38,7 @@ impl TermSplit { } pub fn validate(&self) -> Result<(), String> { - let mut frame_count: BTreeMap = BTreeMap::new(); + let mut frame_count: BTreeMap = BTreeMap::new(); self.collect_term_frames(&mut frame_count); let duplicate_terminal = frame_count .iter() @@ -103,7 +103,7 @@ impl TermSplit { } } - pub fn hsplit(&self, pathstr: &str, new_frame: TermFrame) -> Result { + pub fn hsplit(&self, pathstr: &str, new_frame: FrameId) -> Result { let new = self.modify_at_pathstr(pathstr, move |n| { Ok(TermSplit::Horizontal { left: n.clone().into(), @@ -114,7 +114,7 @@ impl TermSplit { Ok(new) } - pub fn vsplit(&self, pathstr: &str, new_frame: TermFrame) -> Result { + pub fn vsplit(&self, pathstr: &str, new_frame: FrameId) -> Result { let new = self.modify_at_pathstr(pathstr, move |n| { Ok(TermSplit::Vertical { top: n.clone().into(), @@ -145,19 +145,10 @@ mod tests { use TermSplit::*; assert_eq!( (Vertical { - top: Term { - frame: TermFrame(1) - } - .into(), + top: Term { frame: FrameId(1) }.into(), bottom: Horizontal { - left: Term { - frame: TermFrame(2) - } - .into(), - right: Term { - frame: TermFrame(3) - } - .into(), + left: Term { frame: FrameId(2) }.into(), + right: Term { frame: FrameId(3) }.into(), } .into() }) @@ -171,19 +162,10 @@ mod tests { use TermSplit::*; assert_eq!( (Vertical { - top: Term { - frame: TermFrame(1) - } - .into(), + top: Term { frame: FrameId(1) }.into(), bottom: Horizontal { - left: Term { - frame: TermFrame(1) - } - .into(), - right: Term { - frame: TermFrame(3) - } - .into(), + left: Term { frame: FrameId(1) }.into(), + right: Term { frame: FrameId(3) }.into(), } .into() }) @@ -192,19 +174,10 @@ mod tests { ); assert_eq!( (Vertical { - top: Term { - frame: TermFrame(42) - } - .into(), + top: Term { frame: FrameId(42) }.into(), bottom: Horizontal { - left: Term { - frame: TermFrame(1) - } - .into(), - right: Term { - frame: TermFrame(42) - } - .into(), + left: Term { frame: FrameId(1) }.into(), + right: Term { frame: FrameId(42) }.into(), } .into() }) @@ -216,99 +189,49 @@ mod tests { #[test] fn modify_at_pathstr_works() { use TermSplit::*; - let t = Term { - frame: TermFrame(1), - }; + let t = Term { frame: FrameId(1) }; assert_eq!( - t.modify_at_pathstr("", |_v| { - Ok(Term { - frame: TermFrame(2), - }) - }), - Ok(Term { - frame: TermFrame(2), - }) + t.modify_at_pathstr("", |_v| { Ok(Term { frame: FrameId(2) }) }), + Ok(Term { frame: FrameId(2) }) ); assert_eq!( - t.modify_at_pathstr("tlr", |_v| { - Ok(Term { - frame: TermFrame(2), - }) - }), + t.modify_at_pathstr("tlr", |_v| { Ok(Term { frame: FrameId(2) }) }), Err("In split path, found trailing junk tlr after addressing terminal".to_owned()) ); let t = Vertical { top: Horizontal { left: Horizontal { - left: Term { - frame: TermFrame(42), - } - .into(), - right: Term { - frame: TermFrame(64), - } - .into(), - } - .into(), - right: Term { - frame: TermFrame(42), + left: Term { frame: FrameId(42) }.into(), + right: Term { frame: FrameId(64) }.into(), } .into(), + right: Term { frame: FrameId(42) }.into(), } .into(), bottom: Vertical { - top: Term { - frame: TermFrame(43), - } - .into(), - bottom: Term { - frame: TermFrame(44), - } - .into(), + top: Term { frame: FrameId(43) }.into(), + bottom: Term { frame: FrameId(44) }.into(), } .into(), }; assert_eq!( - t.modify_at_pathstr("tlr", |_v| { - Ok(Term { - frame: TermFrame(2), - }) - }) - .and_then(|t| t.modify_at_pathstr("bb", |_v| { - Ok(Term { - frame: TermFrame(3), - }) - })), + t.modify_at_pathstr("tlr", |_v| { Ok(Term { frame: FrameId(2) }) }) + .and_then(|t| t.modify_at_pathstr("bb", |_v| { Ok(Term { frame: FrameId(3) }) })), Ok(Vertical { top: Horizontal { left: Horizontal { - left: Term { - frame: TermFrame(42), - } - .into(), - right: Term { - frame: TermFrame(2), - } - .into(), - } - .into(), - right: Term { - frame: TermFrame(42), + left: Term { frame: FrameId(42) }.into(), + right: Term { frame: FrameId(2) }.into(), } .into(), + right: Term { frame: FrameId(42) }.into(), } .into(), bottom: Vertical { - top: Term { - frame: TermFrame(43), - } - .into(), - bottom: Term { - frame: TermFrame(3), - } - .into(), + top: Term { frame: FrameId(43) }.into(), + bottom: Term { frame: FrameId(3) }.into(), } .into(), }) diff --git a/src/timer_host.rs b/src/timer_host.rs index 4004773..d14017e 100644 --- a/src/timer_host.rs +++ b/src/timer_host.rs @@ -5,12 +5,12 @@ use wasm_bindgen::{closure::Closure, JsCast}; use crate::{ command_handler::execute_queue, parsing::{parse_commands, ParsedCommand}, - GlobalMemoCell, TermFrame, + FrameId, GlobalMemoCell, }; pub struct TimerHost { timers: Vec, - frame_id: TermFrame, + frame_id: FrameId, next_id: u64, } @@ -29,7 +29,7 @@ impl Drop for TimerHost { } impl TimerHost { - pub fn new(frame_id: TermFrame) -> Self { + pub fn new(frame_id: FrameId) -> Self { Self { timers: vec![], frame_id, diff --git a/styles.css b/styles.css index ac3edca..a6b6a01 100644 --- a/styles.css +++ b/styles.css @@ -67,3 +67,9 @@ body { font-family: "JetBrainsMono-Regular", monospace, serif; font-variant-ligatures: none; } +.editornav { + color: white; +} +.editorarea { + color: white; +}