Skip to content

Commit

Permalink
feat: logging, aborting, Rhai main loop
Browse files Browse the repository at this point in the history
  • Loading branch information
justinpombrio committed Apr 17, 2024
1 parent f9fd0ed commit 2fb0fe8
Show file tree
Hide file tree
Showing 14 changed files with 325 additions and 41 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
Cargo.lock
*.html
.#*
log.txt
15 changes: 15 additions & 0 deletions scripts/base_module.rhai
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
fn block() {
loop {
let keyprog = synless_internals::block_on_key();
if keyprog.close_menu {
s::close_menu();
return call(keyprog.prog);
}
call(keyprog.prog);
}
}

fn abort() {
synless_internals::prepare_to_abort();
exit();
}
Empty file added scripts/init.rhai
Empty file.
Empty file added scripts/internals_module.rhai
Empty file.
22 changes: 22 additions & 0 deletions scripts/main.rhai
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
loop {
try {
s::block(); // ignoring return value
} catch (err) {
if type_of(err) == "SynlessError" {
let category = err.category;
let msg = err.message;
s::log_error(`${category}: ${msg}`);
if err.category == "Abort" {
s::abort();
}
} else {
if type_of(err) == "map" && "message" in err {
let msg = err.message;
s::log_error(`Rhai: ${msg}`);
} else {
s::log_error(`Thrown: ${err}`);
};
}
s::close_menu();
}
}
72 changes: 58 additions & 14 deletions src/editor/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::engine::{DocDisplayLabel, Engine};
use crate::engine::{DocDisplayLabel, Engine, Settings};
use crate::frontends::{Event, Frontend, Key, MouseEvent};
use crate::keymap::{KeyProg, LayerManager};
use crate::style::Style;
use crate::tree::Mode;
use crate::util::{error, SynlessBug, SynlessError};
use crate::util::{error, log, SynlessBug, SynlessError};
use partial_pretty_printer as ppp;
use partial_pretty_printer::pane;
use std::cell::RefCell;
Expand All @@ -17,14 +17,30 @@ pub struct Runtime<F: Frontend<Style = Style>> {
engine: Engine,
pane_notation: pane::PaneNotation<DocDisplayLabel, Style>,
frontend: F,
layer_manager: LayerManager,
layers: LayerManager,
}

impl<F: Frontend<Style = Style> + 'static> Runtime<F> {
pub fn abort(&mut self, err: SynlessError) -> ! {
//self.engine.report_error(&err);
// TODO: Save the error log, and maybe the docs
panic!("{}", err);
pub fn new(settings: Settings, frontend: F) -> Runtime<F> {
let engine = Engine::new(settings);
let pane_notation = pane::PaneNotation::Doc {
label: DocDisplayLabel::Visible,
};
Runtime {
engine,
pane_notation,
frontend,
layers: LayerManager::new(),
}
}

pub fn close_menu(&mut self) {
self.layers.close_menu();
}

pub fn prepare_to_abort(&mut self) {
log!(Error, "Synless is aborting!");
// TODO try to save docs
}

pub fn display(&mut self) -> Result<(), SynlessError> {
Expand All @@ -48,8 +64,8 @@ impl<F: Frontend<Style = Style> + 'static> Runtime<F> {
loop {
match self.next_event()? {
// TODO: Remove Ctrl-c. It's only for testing.
Event::Key(ctrl_c) => {
return Err(error!(Event, "I was rudely interrupted by Ctrl-C"));
Event::Key(key) if key == ctrl_c => {
return Err(error!(Abort, "I was rudely interrupted by Ctrl-C"));
}
Event::Key(key) => {
if let Some(prog) = self.lookup_key(key) {
Expand All @@ -74,7 +90,7 @@ impl<F: Frontend<Style = Style> + 'static> Runtime<F> {
}
};

self.layer_manager.lookup_key(mode, doc_name, key)
self.layers.lookup_key(mode, doc_name, key)
}

/// Block until the next input event.
Expand All @@ -99,13 +115,41 @@ macro_rules! register {
.in_internal_namespace()
.set_into_module($module, closure);
};
($module:expr, $runtime:ident . $method:ident($( $param:ident : $type:ty ),*) ? ) => {
let rt = $runtime.clone();
let closure = move | $( $param : $type ),* | {
rt.borrow_mut().$method( $( $param ),* )
.map_err(|err| Box::<rhai::EvalAltResult>::from(err))
};
rhai::FuncRegistration::new(stringify!($method))
.in_internal_namespace()
.set_into_module($module, closure);
};
}

impl<F: Frontend<Style = Style> + 'static> Runtime<F> {
fn register_runtime_methods(self, module: &mut rhai::Module) {
let rt = Rc::new(RefCell::new(self));
pub fn register_internal_methods(rt: Rc<RefCell<Runtime<F>>>, module: &mut rhai::Module) {
register!(module, rt.prepare_to_abort());
register!(module, rt.block_on_key()?);
}

pub fn register_external_methods(rt: Rc<RefCell<Runtime<F>>>, module: &mut rhai::Module) {
register!(module, rt.close_menu());

register!(module, rt.block_on_key());
register!(module, rt.abort(err: SynlessError));
rhai::FuncRegistration::new("log_trace")
.in_internal_namespace()
.set_into_module(module, |msg: String| log!(Trace, "{}", msg));
rhai::FuncRegistration::new("log_debug")
.in_internal_namespace()
.set_into_module(module, |msg: String| log!(Debug, "{}", msg));
rhai::FuncRegistration::new("log_info")
.in_internal_namespace()
.set_into_module(module, |msg: String| log!(Info, "{}", msg));
rhai::FuncRegistration::new("log_warn")
.in_internal_namespace()
.set_into_module(module, |msg: String| log!(Warn, "{}", msg));
rhai::FuncRegistration::new("log_error")
.in_internal_namespace()
.set_into_module(module, |msg: String| log!(Error, "{}", msg));
}
}
3 changes: 0 additions & 3 deletions src/frontends/frontend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ pub use crate::style::ColorTheme;
/// A front end for the editor. It knows how to render a frame and how to
/// receive keyboard and mouse events.
pub trait Frontend: Sized + ppp::pane::PrettyWindow {
/// Construct a new frontend.
fn new(theme: ColorTheme) -> Result<Self, Self::Error>;

/// Set the color theme. Must not be called between `start_frame()` and `end_frame()`.
fn set_color_theme(&mut self, theme: ColorTheme) -> Result<(), Self::Error>;

Expand Down
2 changes: 1 addition & 1 deletion src/frontends/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl<W: Error + 'static, E: Error + 'static> From<pane::PaneError<W, E>> for Syn
match &error {
InvalidUseOfDynamic | MissingDocument(_) => error!(Frontend, "{}", error.to_string()),
PrettyWindowError(err) => error!(Frontend, "{}", err.to_string()),
PrintingError(err) => error!(Frontend, "{}", err.to_string()),
PrintingError(err) => error!(Printing, "{}", err.to_string()),
}
}
}
24 changes: 12 additions & 12 deletions src/frontends/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ pub enum TerminalError {
}

impl Terminal {
pub fn new(theme: ColorTheme) -> Result<Terminal, TerminalError> {
let default_concrete_style = theme.concrete_style(&Style::default());

let mut term = Terminal {
color_theme: theme,
buf: ScreenBuf::new(Terminal::terminal_window_size()?, default_concrete_style),
focus_pos: None,
};
term.enter()?;
Ok(term)
}

/// Get the current size of the actual terminal window in characters. This may be different
/// than the current size of the ScreenBuf.
fn terminal_window_size() -> Result<Size, TerminalError> {
Expand Down Expand Up @@ -108,18 +120,6 @@ impl PrettyWindow for Terminal {
}

impl Frontend for Terminal {
fn new(theme: ColorTheme) -> Result<Terminal, TerminalError> {
let default_concrete_style = theme.concrete_style(&Style::default());

let mut term = Terminal {
color_theme: theme,
buf: ScreenBuf::new(Terminal::terminal_window_size()?, default_concrete_style),
focus_pos: None,
};
term.enter()?;
Ok(term)
}

fn set_color_theme(&mut self, theme: ColorTheme) -> Result<(), Self::Error> {
let default_concrete_style = theme.concrete_style(&Style::default());
self.color_theme = theme;
Expand Down
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ pub mod parsing;

pub use editor::Runtime;
pub use engine::{DocName, Engine, Settings};
pub use frontends::Terminal;
pub use keymap::KeyProg;
pub use language::{
AritySpec, ConstructSpec, GrammarSpec, LanguageSpec, NotationSetSpec, SortSpec, Storage,
};
pub use pretty_doc::DocRef;
pub use style::ColorTheme;
pub use tree::{Location, Node};
pub use util::SynlessError;
pub use util::{Log, LogEntry, LogLevel, SynlessBug, SynlessError};
84 changes: 80 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,83 @@
use synless::{Engine, Settings};
use std::cell::RefCell;
use std::rc::Rc;
use synless::{log, ColorTheme, Log, Runtime, Settings, SynlessBug, Terminal};

fn main() {
Engine::new(Settings::default());
// TODO: Make this work if you start in a different cwd
const BASE_MODULE_PATH: &str = "scripts/base_module.rhai";
const INTERNALS_MODULE_PATH: &str = "scripts/internals_module.rhai";
const INIT_PATH: &str = "scripts/init.rhai";
const MAIN_PATH: &str = "scripts/main.rhai";

fn make_engine() -> rhai::Engine {
let mut engine = rhai::Engine::new();
engine.set_fail_on_invalid_map_property(true);
engine.on_print(|msg| log!(Info, "{msg}"));
engine.on_debug(|msg, src, pos| {
let src = src.unwrap_or("unknown");
log!(Debug, "{src} @ {pos:?} > {msg}");
});

engine.build_type::<synless::KeyProg>();
engine.build_type::<synless::SynlessError>();

println!("Signatures:");
engine
.gen_fn_signatures(false)
.into_iter()
.for_each(|func| println!(" {func}"));
println!();

engine
}

fn make_runtime() -> Rc<RefCell<Runtime<Terminal>>> {
let settings = Settings::default();
let terminal =
Terminal::new(ColorTheme::default_dark()).bug_msg("Failed to construct terminal frontend");
let runtime = Runtime::new(settings, terminal);
Rc::new(RefCell::new(runtime))
}

fn run() -> Result<(), Box<rhai::EvalAltResult>> {
let mut engine = make_engine();

panic!("not yet implemented");
// Load internals_module.rhai
let mut internals_mod = {
let internals_ast = engine.compile_file(INTERNALS_MODULE_PATH.into())?;
rhai::Module::eval_ast_as_new(rhai::Scope::new(), &internals_ast, &engine)?
};

// Load base_module.rhai
let mut base_mod = {
let base_ast = engine.compile_file(BASE_MODULE_PATH.into())?;
rhai::Module::eval_ast_as_new(rhai::Scope::new(), &base_ast, &engine)?
};

// Register runtime methods into internals_module and base_module
let runtime = make_runtime();
Runtime::register_internal_methods(runtime.clone(), &mut internals_mod);
engine.register_static_module("synless_internals", internals_mod.into());
Runtime::register_external_methods(runtime, &mut base_mod);
engine.register_static_module("s", base_mod.into());

// Can't set this before modules are registered, as they reference each other
engine.set_strict_variables(true);

// Load init.rhai
let init_ast = engine.compile_file(INIT_PATH.into())?;
engine.run_ast(&init_ast)?;

// Load main.rhai
let main_ast = engine.compile_file(MAIN_PATH.into())?;
engine.run_ast(&main_ast)?;

Ok(())
}

fn main() {
log!(Info, "Synless is starting");
if let Err(err) = run() {
log!(Error, "{}", err);
}
println!("{}", Log::to_string());
}
22 changes: 16 additions & 6 deletions src/util/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ pub struct SynlessError {
pub category: ErrorCategory,
}

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorCategory {
Doc,
Edit,
Frontend,
Language,
Parse,
Printing,
Event,
Escape,
Abort,
}

impl fmt::Display for ErrorCategory {
Expand All @@ -32,7 +33,7 @@ impl ErrorCategory {

match self {
Edit => false,
Doc | Frontend | Language | Parse | Printing | Event => true,
Doc | Frontend | Language | Parse | Printing | Escape | Abort => true,
}
}
}
Expand Down Expand Up @@ -66,15 +67,24 @@ macro_rules! error {
impl rhai::CustomType for SynlessError {
fn build(mut builder: rhai::TypeBuilder<Self>) {
builder
.with_name("Error")
.with_name("SynlessError")
.with_get("message", |err: &mut SynlessError| -> String {
err.message.clone()
})
.with_get("category", |err: &mut SynlessError| -> ErrorCategory {
err.category
.with_get("category", |err: &mut SynlessError| -> String {
format!("{}", err.category)
})
.with_fn("is_fatal", |err: &mut SynlessError| -> bool {
err.is_fatal()
});
}
}

impl From<SynlessError> for Box<rhai::EvalAltResult> {
fn from(error: SynlessError) -> Box<rhai::EvalAltResult> {
Box::new(rhai::EvalAltResult::ErrorRuntime(
rhai::Dynamic::from(error),
rhai::Position::NONE,
))
}
}
Loading

0 comments on commit 2fb0fe8

Please sign in to comment.