-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Many partially implemented features (app, runtime, prog, layers)
- Loading branch information
1 parent
d152f8f
commit 194605d
Showing
16 changed files
with
638 additions
and
130 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
use super::runtime::Runtime; | ||
use super::stack::{CallStack, DataStack, Op, Prog}; | ||
use super::EditorError; | ||
use crate::engine::Engine; | ||
use crate::frontends::{Event, Frontend, Key, MouseEvent}; | ||
use crate::style::Style; | ||
use crate::util::SynlessBug; | ||
use std::time::Duration; | ||
|
||
/* | ||
* ## Control flow | ||
* | ||
* To execute a program in the interpreter (w/ call stack, data stack, engine): | ||
* | ||
* ``` | ||
* PUSH the program onto the call stack | ||
* REPEAT pop op off call stack and execute it | ||
* IF the op is `block` or the call stack becomes empty: | ||
* THEN suspend the interpreter and return to the server. | ||
* ``` | ||
* | ||
* To run the server: | ||
* | ||
* ``` | ||
* SET the current keymap: | ||
* IF there's a menu | ||
* THEN use the menu's keymap | ||
* ELSE use the current mode's tree or text keymap | ||
* DISPLAY the screen | ||
* BLOCK until a key is pressed | ||
* THEN execute that key's prog in the interpreter | ||
* ``` | ||
* | ||
* To execute a KeyProg: | ||
* | ||
* ``` | ||
* IF push_string: | ||
* THEN push selected string onto data stack | ||
* IF exit_menu: | ||
* THEN exit the menu | ||
* EXECUTE program | ||
* IF !exit_menu: | ||
* THEN block | ||
* ``` | ||
*/ | ||
|
||
struct App<F: Frontend<Style = Style>> { | ||
runtime: Runtime<F>, | ||
call_stack: CallStack, | ||
data_stack: DataStack, | ||
} | ||
|
||
impl<F: Frontend<Style = Style>> App<F> { | ||
pub fn run_event_loop(&mut self) { | ||
loop { | ||
if let Err(err) = self.runtime.display() { | ||
self.abort(err); | ||
} | ||
let prog = match self.block_on_input() { | ||
Ok(prog) => prog, | ||
Err(err) => self.abort(err), | ||
}; | ||
match self.execute(prog) { | ||
Ok(()) => (), | ||
Err(err) => self.runtime.engine.report_error(&err), | ||
} | ||
} | ||
} | ||
|
||
fn execute(&mut self, prog: Prog) -> Result<(), EditorError> { | ||
self.call_stack.push(prog); | ||
while let Some(op) = self.call_stack.pop() { | ||
if op == Op::Block { | ||
return Ok(()); | ||
} else { | ||
self.call(op)?; | ||
} | ||
} | ||
Ok(()) | ||
} | ||
|
||
fn block_on_input(&mut self) -> Result<Prog, EditorError> { | ||
use std::str::FromStr; | ||
|
||
let ctrl_c = Key::from_str("C-c").bug(); | ||
|
||
loop { | ||
match self.runtime.next_event()? { | ||
// TODO: Remove Ctrl-c. It's only for testing. | ||
Event::Key(ctrl_c) => return Err(EditorError::KeyboardInterrupt), | ||
Event::Key(key) => { | ||
if let Some(prog) = self.runtime.lookup_key(key) { | ||
return Ok(prog); | ||
} | ||
// wait for a better key press | ||
} | ||
Event::Resize => self.runtime.display()?, | ||
Event::Mouse(_) => (), | ||
Event::Paste(_) => (), // TODO: OS paste support | ||
} | ||
} | ||
} | ||
|
||
fn call(&mut self, op: Op) -> Result<(), EditorError> { | ||
todo!() | ||
} | ||
|
||
fn abort(&mut self, err: EditorError) -> ! { | ||
self.runtime.engine.report_error(&err); | ||
// TODO: Save the error log, and maybe the docs | ||
panic!("{}", err); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
use super::keymap::Keymap; | ||
use crate::tree::Mode; | ||
use crate::util::IndexedMap; | ||
use std::collections::HashMap; | ||
|
||
type MenuName = String; | ||
type LayerIndex = usize; | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
enum KeymapLabel { | ||
Menu(MenuName), | ||
Mode(Mode), | ||
} | ||
|
||
pub struct Layer { | ||
name: String, | ||
keymaps: HashMap<KeymapLabel, Keymap>, | ||
} | ||
|
||
impl Layer { | ||
pub fn new(name: String) -> Layer { | ||
Layer { | ||
name, | ||
keymaps: HashMap::new(), | ||
} | ||
} | ||
|
||
pub fn add_menu(&mut self, menu_name: MenuName, keymap: Keymap) { | ||
self.keymaps.insert(KeymapLabel::Menu(menu_name), keymap); | ||
} | ||
|
||
pub fn add_mode(&mut self, mode: Mode, keymap: Keymap) { | ||
self.keymaps.insert(KeymapLabel::Mode(mode), keymap); | ||
} | ||
} | ||
|
||
// TODO: Have LayerManager track DocName -> local_layers? | ||
// | ||
// local: Buffer -> Vec<LayerIndex> | ||
// global: Vec<LayerIndex> | ||
// | ||
// order: buffer, global | ||
|
||
pub struct LayerManager { | ||
active_local_layers: Vec<LayerIndex>, | ||
active_global_layers: Vec<LayerIndex>, | ||
active_menu: Option<MenuName>, | ||
layers: IndexedMap<Layer>, | ||
} | ||
|
||
impl LayerManager { | ||
pub fn add_layer(&mut self, layer: Layer) { | ||
self.layers.insert(layer.name.clone(), layer); | ||
} | ||
|
||
pub fn enter_menu(&mut self, menu_name: String) { | ||
self.active_menu = Some(menu_name); | ||
} | ||
|
||
pub fn exit_menu(&mut self) { | ||
self.active_menu = None; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,26 @@ | ||
mod app; | ||
mod keymap; | ||
mod layer; | ||
mod runtime; | ||
mod stack; | ||
|
||
use crate::engine::EngineError; | ||
use crate::frontends::Frontend; | ||
use std::error::Error; | ||
use std::fmt; | ||
|
||
#[derive(thiserror::Error, fmt::Debug)] | ||
pub enum EditorError { | ||
#[error("Error from the document engine")] | ||
EngineError(#[from] EngineError), | ||
#[error("Attempted to pop an empty data stack")] | ||
EmptyDataStack, | ||
#[error("Expected type '{expected}' but found '{actual}'")] | ||
TypeMismatch { actual: String, expected: String }, | ||
#[error("I was rudely interrupted by Ctrl-C")] | ||
KeyboardInterrupt, | ||
#[error("Frontend error")] | ||
FrontendError(#[source] Box<dyn Error>), | ||
#[error("Pane error")] | ||
PaneError(#[source] Box<dyn Error>), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use super::stack::Prog; | ||
use super::EditorError; | ||
use crate::engine::{DocDisplayLabel, Engine}; | ||
use crate::frontends::{Event, Frontend, Key}; | ||
use crate::style::Style; | ||
use partial_pretty_printer as ppp; | ||
use partial_pretty_printer::pane; | ||
use std::error::Error; | ||
use std::time::Duration; | ||
|
||
pub struct Runtime<F: Frontend<Style = Style>> { | ||
pub engine: Engine, | ||
pane_notation: pane::PaneNotation<DocDisplayLabel, Style>, | ||
frontend: F, | ||
} | ||
|
||
impl<F: Frontend<Style = Style>> Runtime<F> { | ||
/// Block until the next input event. | ||
pub fn next_event(&mut self) -> Result<Event, EditorError> { | ||
loop { | ||
match self.frontend.next_event(Duration::from_secs(1)) { | ||
Ok(None) => (), // continue waiting | ||
Ok(Some(event)) => return Ok(event), | ||
Err(err) => return Err(EditorError::FrontendError(Box::new(err))), | ||
} | ||
} | ||
} | ||
|
||
pub fn display(&mut self) -> Result<(), EditorError> { | ||
self.frontend | ||
.start_frame() | ||
.map_err(|err| EditorError::FrontendError(Box::new(err)))?; | ||
|
||
let get_content = |doc_label| self.engine.get_content(doc_label); | ||
pane::display_pane(&mut self.frontend, &self.pane_notation, &get_content) | ||
.map_err(|err| EditorError::PaneError(Box::new(err)))?; | ||
|
||
self.frontend | ||
.end_frame() | ||
.map_err(|err| EditorError::FrontendError(Box::new(err))) | ||
} | ||
|
||
pub fn lookup_key(&self, key: Key) -> Option<Prog> { | ||
// TODO: must handle char insertion in text mode | ||
todo!() | ||
} | ||
} |
Oops, something went wrong.