-
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.
Merge pull request #17 from justinpombrio/demo-ed-concat-lang
Draft concatenative language for demo editor
- Loading branch information
Showing
21 changed files
with
1,340 additions
and
377 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
[package] | ||
name = "synless" | ||
version = "0.0.1" | ||
authors = ["justinpombrio <[email protected]>"] | ||
authors = ["justinpombrio <[email protected]>", "e-matteson <[email protected]>"] | ||
|
||
[workspace] | ||
members = [ | ||
|
@@ -10,11 +10,13 @@ members = [ | |
"pretty", | ||
"language", | ||
"frontends", | ||
"editor"] | ||
"editor", | ||
"demo"] | ||
default-members = [ | ||
"utility", | ||
"forest", | ||
"pretty", | ||
"language", | ||
"frontends", | ||
"editor"] | ||
"editor", | ||
"demo"] |
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,15 @@ | ||
[package] | ||
name = "demo" | ||
version = "0.1.0" | ||
authors = ["e-matteson <[email protected]>"] | ||
edition = "2018" | ||
|
||
[dependencies] | ||
editor = { path = "../editor" } | ||
forest = { path = "../forest" } | ||
pretty = { path = "../pretty" } | ||
language = { path = "../language" } | ||
frontends = { path = "../frontends"} | ||
utility = { path = "../utility"} | ||
lazy_static = "*" | ||
termion = "1.5" |
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,36 @@ | ||
use std::io; | ||
use termion::event::Key; | ||
|
||
use frontends::terminal; | ||
use language::{ConstructName, LanguageName}; | ||
|
||
#[derive(Debug)] | ||
pub enum Error { | ||
UnknownKey(Key), | ||
UnknownKeymap(String), | ||
NoKeymap, | ||
UnknownEvent, | ||
KeyboardInterrupt, | ||
UnknownLang(LanguageName), | ||
UnknownConstruct { | ||
construct: ConstructName, | ||
lang: LanguageName, | ||
}, | ||
ExpectedWord(String), | ||
EmptyStack, | ||
DocExec(String), | ||
Io(io::Error), | ||
Term(terminal::Error), | ||
} | ||
|
||
impl From<io::Error> for Error { | ||
fn from(e: io::Error) -> Error { | ||
Error::Io(e) | ||
} | ||
} | ||
|
||
impl From<terminal::Error> for Error { | ||
fn from(e: terminal::Error) -> Error { | ||
Error::Term(e) | ||
} | ||
} |
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,212 @@ | ||
use std::collections::HashMap; | ||
use std::iter; | ||
use termion::event::Key; | ||
|
||
use crate::prog::{Prog, Word}; | ||
use language::{Language, LanguageName}; | ||
|
||
pub struct Keymap<'l>(pub HashMap<Key, Prog<'l>>); | ||
|
||
impl<'l> Keymap<'l> { | ||
pub fn node(lang: &Language) -> Self { | ||
Keymap( | ||
lang.keymap() | ||
.iter() | ||
.map(|(&ch, construct_name)| { | ||
( | ||
Key::Char(ch), | ||
Prog::named( | ||
construct_name, | ||
&[ | ||
// Push the new node onto the stack, and then | ||
// apply the quoted command (eg. InsertAfter) | ||
// that was already on the top of the stack. | ||
Word::LangConstruct(lang.name().into(), construct_name.to_owned()), | ||
Word::NodeByName, | ||
Word::Swap, | ||
Word::Apply, | ||
Word::PopMap, | ||
], | ||
), | ||
) | ||
}) | ||
.chain(iter::once(( | ||
Key::Esc, | ||
Prog::named( | ||
"Cancel", | ||
&[ | ||
Word::Pop, // get rid of the quoted command on the stack | ||
Word::PopMap, | ||
], | ||
), | ||
))) | ||
.collect(), | ||
) | ||
} | ||
|
||
pub fn tree() -> Self { | ||
let map = vec![ | ||
(Key::Char('d'), Prog::single(Word::Cut)), | ||
(Key::Char('y'), Prog::single(Word::Copy)), | ||
(Key::Char('p'), Prog::single(Word::PasteAfter)), | ||
(Key::Char('P'), Prog::single(Word::PasteBefore)), | ||
(Key::Ctrl('p'), Prog::single(Word::PastePrepend)), | ||
(Key::Alt('p'), Prog::single(Word::PastePostpend)), | ||
(Key::Char('R'), Prog::single(Word::PasteReplace)), | ||
( | ||
Key::Char('a'), | ||
Prog::named("TypeA", &[Word::Char('a'), Word::InsertChar]), | ||
), | ||
(Key::Char('u'), Prog::single(Word::Undo)), | ||
(Key::Ctrl('r'), Prog::single(Word::Redo)), | ||
(Key::Right, Prog::single(Word::Right)), | ||
(Key::Left, Prog::single(Word::Left)), | ||
(Key::Up, Prog::single(Word::Parent)), | ||
(Key::Backspace, Prog::single(Word::Remove)), | ||
( | ||
Key::Down, | ||
Prog::named("Child", &[Word::Usize(0), Word::Child]), | ||
), | ||
( | ||
Key::Char('i'), | ||
Prog::named( | ||
"InsertAfter", | ||
&[ | ||
Word::InsertAfter.quote(), | ||
Word::MapName("node".into()), | ||
Word::PushMap, | ||
], | ||
), | ||
), | ||
( | ||
Key::Char('I'), | ||
Prog::named( | ||
"InsertBefore", | ||
&[ | ||
Word::InsertBefore.quote(), | ||
Word::MapName("node".into()), | ||
Word::PushMap, | ||
], | ||
), | ||
), | ||
( | ||
Key::Char('o'), | ||
Prog::named( | ||
"InsertPostpend", | ||
&[ | ||
Word::InsertPostpend.quote(), | ||
Word::MapName("node".into()), | ||
Word::PushMap, | ||
], | ||
), | ||
), | ||
( | ||
Key::Char('O'), | ||
Prog::named( | ||
"InsertPrepend", | ||
&[ | ||
Word::InsertPrepend.quote(), | ||
Word::MapName("node".into()), | ||
Word::PushMap, | ||
], | ||
), | ||
), | ||
( | ||
Key::Char('r'), | ||
Prog::named( | ||
"Replace", | ||
&[ | ||
Word::Replace.quote(), | ||
Word::MapName("node".into()), | ||
Word::PushMap, | ||
], | ||
), | ||
), | ||
( | ||
Key::Char(' '), | ||
Prog::named( | ||
"SpeedBoolMode", | ||
&[Word::MapName("speed_bool".into()), Word::PushMap], | ||
), | ||
), | ||
] | ||
.into_iter() | ||
.collect(); | ||
|
||
Keymap(map) | ||
} | ||
|
||
pub fn speed_bool() -> Self { | ||
let lang: LanguageName = "json".into(); | ||
let map = vec![ | ||
( | ||
Key::Char('t'), | ||
Prog::named( | ||
"True", | ||
&[ | ||
Word::LangConstruct(lang.clone(), "true".into()), | ||
Word::NodeByName, | ||
Word::InsertAfter, | ||
], | ||
), | ||
), | ||
( | ||
Key::Char('f'), | ||
Prog::named( | ||
"False", | ||
&[ | ||
Word::LangConstruct(lang, "false".into()), | ||
Word::NodeByName, | ||
Word::InsertAfter, | ||
], | ||
), | ||
), | ||
(Key::Esc, Prog::named("Exit", &[Word::PopMap])), | ||
] | ||
.into_iter() | ||
.collect(); | ||
|
||
Keymap(map) | ||
} | ||
|
||
pub fn summary(&self) -> String { | ||
let mut s = String::new(); | ||
for (key, prog) in &self.0 { | ||
let prog_name = if let Some(ref name) = prog.name { | ||
name.to_string() | ||
} else if prog.words.len() == 1 { | ||
format!("{:?}", prog.words[0]) | ||
} else { | ||
"...".into() | ||
}; | ||
s += &format!("{}:{}, ", self.format_key(key), prog_name); | ||
} | ||
s | ||
} | ||
|
||
fn format_key(&self, key: &Key) -> String { | ||
match key { | ||
Key::Backspace => "Bksp".to_string(), | ||
Key::Left => "←".to_string(), | ||
Key::Right => "→".to_string(), | ||
Key::Up => "↑".to_string(), | ||
Key::Down => "↓".to_string(), | ||
Key::Home => "Home".to_string(), | ||
Key::End => "End".to_string(), | ||
Key::PageUp => "PgUp".to_string(), | ||
Key::PageDown => "PgDn".to_string(), | ||
Key::Delete => "Del".to_string(), | ||
Key::Insert => "Ins".to_string(), | ||
Key::F(num) => format!("F{}", num), | ||
Key::Char(' ') => "Spc".to_string(), | ||
Key::Char(c) => c.to_string(), | ||
Key::Alt(' ') => "A-Spc".to_string(), | ||
Key::Alt(c) => format!("A-{}", c), | ||
Key::Ctrl(' ') => "C-Spc".to_string(), | ||
Key::Ctrl(c) => format!("C-{}", c), | ||
Key::Null => "Null".to_string(), | ||
Key::Esc => "Esc".to_string(), | ||
_ => "(unknown)".to_string(), | ||
} | ||
} | ||
} |
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,70 @@ | ||
use crate::NotationSet; | ||
use language::{Arity, Construct, Language}; | ||
use pretty::{child, literal, no_wrap, repeat, text, Notation, Repeat, Style}; | ||
|
||
pub fn make_keymap_lang() -> (Language, NotationSet) { | ||
let notations = vec![ | ||
("key".into(), key()), | ||
("prog".into(), prog()), | ||
("entry".into(), entry()), | ||
("dict".into(), dict()), | ||
]; | ||
let constructs = vec![ | ||
Construct::new("key", "Key", Arity::Text, Some('k')), | ||
Construct::new("prog", "Value", Arity::Text, Some('p')), | ||
Construct::new( | ||
"dict", | ||
"Dict", | ||
Arity::Flexible("Entry".to_string()), | ||
Some('d'), | ||
), | ||
Construct::new( | ||
"entry", | ||
"Entry", | ||
Arity::Fixed(vec!["Key".to_string(), "Value".to_string()]), | ||
Some('e'), | ||
), | ||
]; | ||
// TODO: some of this boilerplate should get abstracted out | ||
let mut lang = Language::new("keymap"); | ||
for construct in constructs { | ||
lang.add(construct); | ||
} | ||
let note_set = NotationSet::new(&lang, notations); | ||
(lang, note_set) | ||
} | ||
|
||
fn key() -> Notation { | ||
let style = Style::plain(); | ||
text(style) | ||
} | ||
|
||
fn prog() -> Notation { | ||
let style = Style::plain(); | ||
text(style) | ||
} | ||
|
||
/// Try putting the key and value on the same line. | ||
/// If they don't fit, wrap after the colon, and indent the value. | ||
fn entry() -> Notation { | ||
no_wrap(child(0) + punct(": ") + child(1)) | (child(0) + punct(":") ^ indent() + child(1)) | ||
} | ||
|
||
/// Put all entries on separate lines. | ||
/// If there is more than one entry, put the opening and closing delimiters on separate lines too. | ||
fn dict() -> Notation { | ||
repeat(Repeat { | ||
empty: punct("{}"), | ||
lone: punct("{") + child(0) + punct("}"), | ||
join: child(0) + punct(",") ^ child(1), | ||
surround: punct("{") ^ indent() + child(0) ^ punct("}"), | ||
}) | ||
} | ||
|
||
fn punct(text: &str) -> Notation { | ||
literal(text, Style::plain()) | ||
} | ||
|
||
fn indent() -> Notation { | ||
literal(" ", Style::plain()) | ||
} |
Oops, something went wrong.