Render runtime split-screen layout.
This commit is contained in:
		
							parent
							
								
									a002ac1c69
								
							
						
					
					
						commit
						525f69296e
					
				
							
								
								
									
										10
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/main.rs
									
									
									
									
									
								
							@ -1,6 +1,7 @@
 | 
			
		||||
use std::cell::RefCell;
 | 
			
		||||
use std::rc::Rc;
 | 
			
		||||
 | 
			
		||||
use term_split::TermSplit;
 | 
			
		||||
use yew::prelude::*;
 | 
			
		||||
 | 
			
		||||
pub mod command_handler;
 | 
			
		||||
@ -8,6 +9,7 @@ pub mod lineengine;
 | 
			
		||||
pub mod lua_state;
 | 
			
		||||
pub mod parsing;
 | 
			
		||||
pub mod split_panel;
 | 
			
		||||
pub mod term_split;
 | 
			
		||||
pub mod term_view;
 | 
			
		||||
use crate::lua_state::{install_lua_globals, LuaState};
 | 
			
		||||
use crate::split_panel::*;
 | 
			
		||||
@ -18,6 +20,7 @@ pub struct GlobalState {
 | 
			
		||||
    // No strong references allowed between each of these groups of state.
 | 
			
		||||
    frame_registry: RefCell<RegisteredTermFrames>,
 | 
			
		||||
    lua_engine: RefCell<LuaState>,
 | 
			
		||||
    term_splits: RefCell<TermSplit>,
 | 
			
		||||
}
 | 
			
		||||
type GlobalCell = Rc<GlobalState>;
 | 
			
		||||
 | 
			
		||||
@ -35,13 +38,16 @@ fn app() -> Html {
 | 
			
		||||
    let global = use_memo((), |_| GlobalState {
 | 
			
		||||
        frame_registry: RegisteredTermFrames::new().into(),
 | 
			
		||||
        lua_engine: LuaState::setup().expect("Can create interpreter").into(),
 | 
			
		||||
        term_splits: TermSplit::Term {
 | 
			
		||||
            frame: TermFrame(1),
 | 
			
		||||
        }
 | 
			
		||||
        .into(),
 | 
			
		||||
    });
 | 
			
		||||
    install_lua_globals(&global).expect("Couldn't install Lua globals");
 | 
			
		||||
 | 
			
		||||
    html! {
 | 
			
		||||
        <div class="toplevel">
 | 
			
		||||
            <SplitPanel direction={PanelDirection::Vertical} first={ html! { <TermView terminal={TermFrame(0)} global={global.clone()}/> }}
 | 
			
		||||
        second={ html! { <TermView terminal={TermFrame(1)} global={global.clone()}/> } }/>
 | 
			
		||||
            <TermViewTree global={global.clone()}/>
 | 
			
		||||
        </div>
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -128,7 +128,7 @@ mod tests {
 | 
			
		||||
            parse_commands(""),
 | 
			
		||||
            ParseResult {
 | 
			
		||||
                commands: vec![ParsedCommand {
 | 
			
		||||
                    arguments: vec![""]
 | 
			
		||||
                    arguments: vec![""].into()
 | 
			
		||||
                }]
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
@ -136,7 +136,7 @@ mod tests {
 | 
			
		||||
            parse_commands("north"),
 | 
			
		||||
            ParseResult {
 | 
			
		||||
                commands: vec![ParsedCommand {
 | 
			
		||||
                    arguments: vec!["north"]
 | 
			
		||||
                    arguments: vec!["north"].into()
 | 
			
		||||
                }]
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
@ -145,7 +145,7 @@ mod tests {
 | 
			
		||||
            ParseResult {
 | 
			
		||||
                commands: vec![ParsedCommand {
 | 
			
		||||
                    // This is deliberate, ensures we can reconstruct the input.
 | 
			
		||||
                    arguments: vec!["north", ""]
 | 
			
		||||
                    arguments: vec!["north", ""].into()
 | 
			
		||||
                }]
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
@ -154,10 +154,10 @@ mod tests {
 | 
			
		||||
            ParseResult {
 | 
			
		||||
                commands: vec![
 | 
			
		||||
                    ParsedCommand {
 | 
			
		||||
                        arguments: vec!["#blah", "{x = 1 + 2; y = 3}"]
 | 
			
		||||
                        arguments: vec!["#blah", "{x = 1 + 2; y = 3}"].into()
 | 
			
		||||
                    },
 | 
			
		||||
                    ParsedCommand {
 | 
			
		||||
                        arguments: vec!["#home"]
 | 
			
		||||
                        arguments: vec!["#home"].into()
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
@ -166,7 +166,7 @@ mod tests {
 | 
			
		||||
            parse_commands("#blah {x = 1 + 2"),
 | 
			
		||||
            ParseResult {
 | 
			
		||||
                commands: vec![ParsedCommand {
 | 
			
		||||
                    arguments: vec!["#blah", "{x = 1 + 2"]
 | 
			
		||||
                    arguments: vec!["#blah", "{x = 1 + 2"].into()
 | 
			
		||||
                },]
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
@ -174,7 +174,7 @@ mod tests {
 | 
			
		||||
            parse_commands("#blah {x = 1} {y = 1}"),
 | 
			
		||||
            ParseResult {
 | 
			
		||||
                commands: vec![ParsedCommand {
 | 
			
		||||
                    arguments: vec!["#blah", "{x = 1}", "{y = 1}"]
 | 
			
		||||
                    arguments: vec!["#blah", "{x = 1}", "{y = 1}"].into()
 | 
			
		||||
                }]
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
@ -182,7 +182,7 @@ mod tests {
 | 
			
		||||
            parse_commands("#blah \"hello\" \"world\""),
 | 
			
		||||
            ParseResult {
 | 
			
		||||
                commands: vec![ParsedCommand {
 | 
			
		||||
                    arguments: vec!["#blah", "\"hello\"", "\"world\""]
 | 
			
		||||
                    arguments: vec!["#blah", "\"hello\"", "\"world\""].into()
 | 
			
		||||
                }]
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
@ -190,7 +190,7 @@ mod tests {
 | 
			
		||||
            parse_commands("#blah {x = \"}\"} {y = 1}"),
 | 
			
		||||
            ParseResult {
 | 
			
		||||
                commands: vec![ParsedCommand {
 | 
			
		||||
                    arguments: vec!["#blah", "{x = \"}\"}", "{y = 1}"]
 | 
			
		||||
                    arguments: vec!["#blah", "{x = \"}\"}", "{y = 1}"].into()
 | 
			
		||||
                }]
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
@ -204,9 +204,10 @@ mod tests {
 | 
			
		||||
                            "{x = \"}\"; a = \"{\"; y = {}; z = 1;}",
 | 
			
		||||
                            "{ q = 5 }"
 | 
			
		||||
                        ]
 | 
			
		||||
                        .into()
 | 
			
		||||
                    },
 | 
			
		||||
                    ParsedCommand {
 | 
			
		||||
                        arguments: vec![""]
 | 
			
		||||
                        arguments: vec![""].into()
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
@ -215,7 +216,7 @@ mod tests {
 | 
			
		||||
            parse_commands("#blah {\\}\\}\\}} {y = 1}"),
 | 
			
		||||
            ParseResult {
 | 
			
		||||
                commands: vec![ParsedCommand {
 | 
			
		||||
                    arguments: vec!["#blah", "{\\}\\}\\}}", "{y = 1}"]
 | 
			
		||||
                    arguments: vec!["#blah", "{\\}\\}\\}}", "{y = 1}"].into()
 | 
			
		||||
                }]
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
@ -223,7 +224,7 @@ mod tests {
 | 
			
		||||
            parse_commands("#blah \"This is a \\\"test\\\"\""),
 | 
			
		||||
            ParseResult {
 | 
			
		||||
                commands: vec![ParsedCommand {
 | 
			
		||||
                    arguments: vec!["#blah", "\"This is a \\\"test\\\"\""]
 | 
			
		||||
                    arguments: vec!["#blah", "\"This is a \\\"test\\\"\""].into()
 | 
			
		||||
                }]
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										332
									
								
								src/term_split.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								src/term_split.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,332 @@
 | 
			
		||||
use itertools::Itertools;
 | 
			
		||||
use std::collections::BTreeMap;
 | 
			
		||||
 | 
			
		||||
use crate::TermFrame;
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Eq, Debug, Clone)]
 | 
			
		||||
pub enum TermSplit {
 | 
			
		||||
    Term {
 | 
			
		||||
        frame: TermFrame,
 | 
			
		||||
    },
 | 
			
		||||
    Horizontal {
 | 
			
		||||
        left: Box<TermSplit>,
 | 
			
		||||
        right: Box<TermSplit>,
 | 
			
		||||
    },
 | 
			
		||||
    Vertical {
 | 
			
		||||
        top: Box<TermSplit>,
 | 
			
		||||
        bottom: Box<TermSplit>,
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TermSplit {
 | 
			
		||||
    fn collect_term_frames(&self, into: &mut BTreeMap<TermFrame, usize>) {
 | 
			
		||||
        match self {
 | 
			
		||||
            TermSplit::Term { frame } => {
 | 
			
		||||
                into.entry(frame.clone())
 | 
			
		||||
                    .and_modify(|v| *v += 1)
 | 
			
		||||
                    .or_insert(1);
 | 
			
		||||
            }
 | 
			
		||||
            TermSplit::Horizontal { left, right } => {
 | 
			
		||||
                left.collect_term_frames(into);
 | 
			
		||||
                right.collect_term_frames(into);
 | 
			
		||||
            }
 | 
			
		||||
            TermSplit::Vertical { top, bottom } => {
 | 
			
		||||
                top.collect_term_frames(into);
 | 
			
		||||
                bottom.collect_term_frames(into);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn validate(&self) -> Result<(), String> {
 | 
			
		||||
        let mut frame_count: BTreeMap<TermFrame, usize> = BTreeMap::new();
 | 
			
		||||
        self.collect_term_frames(&mut frame_count);
 | 
			
		||||
        let duplicate_terminal = frame_count
 | 
			
		||||
            .iter()
 | 
			
		||||
            .filter_map(|(k, v)| {
 | 
			
		||||
                if *v > 1 {
 | 
			
		||||
                    Some(format!("Terminal {}", k.0))
 | 
			
		||||
                } else {
 | 
			
		||||
                    None
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .join(", ");
 | 
			
		||||
        if !duplicate_terminal.is_empty() {
 | 
			
		||||
            Err(format!(
 | 
			
		||||
                "Attempt to create layout that duplicates reference to: {}",
 | 
			
		||||
                duplicate_terminal
 | 
			
		||||
            ))?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn modify_at_pathstr<F>(&mut self, pathstr: &str, mod_with: F) -> Result<(), String>
 | 
			
		||||
    where
 | 
			
		||||
        F: FnOnce(&mut TermSplit) -> Result<(), String>,
 | 
			
		||||
    {
 | 
			
		||||
        self.modify_at_pathstr_vec(&pathstr.chars().collect::<Vec<char>>(), mod_with)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn modify_at_pathstr_vec<F>(&mut self, pathstr: &[char], mod_with: F) -> Result<(), String>
 | 
			
		||||
    where
 | 
			
		||||
        F: FnOnce(&mut TermSplit) -> Result<(), String>,
 | 
			
		||||
    {
 | 
			
		||||
        match self {
 | 
			
		||||
            TermSplit::Horizontal { left, right } => match pathstr.split_first() {
 | 
			
		||||
                None => mod_with(self),
 | 
			
		||||
                Some(('l', path_rest)) => left.modify_at_pathstr_vec(path_rest, mod_with),
 | 
			
		||||
                Some(('r', path_rest)) => right.modify_at_pathstr_vec(path_rest, mod_with),
 | 
			
		||||
                Some((c, path_rest)) => Err(format!("In split path, found {} before {}, which was unexpected for a horizontal split", c, path_rest.iter().collect::<String>()))
 | 
			
		||||
            },
 | 
			
		||||
            TermSplit::Vertical { top, bottom } => match pathstr.split_first() {
 | 
			
		||||
                None => mod_with(self),
 | 
			
		||||
                Some(('t', path_rest)) => top.modify_at_pathstr_vec(path_rest, mod_with),
 | 
			
		||||
                Some(('b', path_rest)) => bottom.modify_at_pathstr_vec(path_rest, mod_with),
 | 
			
		||||
                Some((c, path_rest)) => Err(format!("In split path, found {} before {}, which was unexpected for a vertical split", c, path_rest.iter().collect::<String>()))
 | 
			
		||||
            },
 | 
			
		||||
            TermSplit::Term { .. } => match pathstr.split_first() {
 | 
			
		||||
                None => mod_with(self),
 | 
			
		||||
                Some(_) => Err(format!("In split path, found trailing junk {} after addressing terminal", pathstr.iter().collect::<String>()))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn hsplit(&mut self, pathstr: &str, new_frame: TermFrame) -> Result<(), String> {
 | 
			
		||||
        let mut new = self.clone();
 | 
			
		||||
        new.modify_at_pathstr(pathstr, move |n| {
 | 
			
		||||
            *n = TermSplit::Horizontal {
 | 
			
		||||
                left: n.clone().into(),
 | 
			
		||||
                right: TermSplit::Term { frame: new_frame }.into(),
 | 
			
		||||
            };
 | 
			
		||||
            Ok(())
 | 
			
		||||
        })?;
 | 
			
		||||
        new.validate()?;
 | 
			
		||||
        *self = new;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn vsplit(&mut self, pathstr: &str, new_frame: TermFrame) -> Result<(), String> {
 | 
			
		||||
        let mut new = self.clone();
 | 
			
		||||
        new.modify_at_pathstr(pathstr, move |n| {
 | 
			
		||||
            *n = TermSplit::Vertical {
 | 
			
		||||
                top: n.clone().into(),
 | 
			
		||||
                bottom: TermSplit::Term { frame: new_frame }.into(),
 | 
			
		||||
            };
 | 
			
		||||
            Ok(())
 | 
			
		||||
        })?;
 | 
			
		||||
        new.validate()?;
 | 
			
		||||
        *self = new;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn join(&mut self, pathstr: &str) -> Result<(), String> {
 | 
			
		||||
        self.modify_at_pathstr(pathstr, move |n| match n {
 | 
			
		||||
            TermSplit::Term { .. } => {
 | 
			
		||||
                Err("Can only join vertical or horizontal splits, not a terminal".to_owned())
 | 
			
		||||
            }
 | 
			
		||||
            TermSplit::Horizontal { left, .. } => {
 | 
			
		||||
                *n = (**left).clone();
 | 
			
		||||
                Ok(())
 | 
			
		||||
            }
 | 
			
		||||
            TermSplit::Vertical { top, .. } => {
 | 
			
		||||
                *n = (**top).clone();
 | 
			
		||||
                Ok(())
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn validate_accepts_valid() {
 | 
			
		||||
        use TermSplit::*;
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            (Vertical {
 | 
			
		||||
                top: Term {
 | 
			
		||||
                    frame: TermFrame(1)
 | 
			
		||||
                }
 | 
			
		||||
                .into(),
 | 
			
		||||
                bottom: Horizontal {
 | 
			
		||||
                    left: Term {
 | 
			
		||||
                        frame: TermFrame(2)
 | 
			
		||||
                    }
 | 
			
		||||
                    .into(),
 | 
			
		||||
                    right: Term {
 | 
			
		||||
                        frame: TermFrame(3)
 | 
			
		||||
                    }
 | 
			
		||||
                    .into(),
 | 
			
		||||
                }
 | 
			
		||||
                .into()
 | 
			
		||||
            })
 | 
			
		||||
            .validate(),
 | 
			
		||||
            Ok(())
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn validate_rejects_duplicate() {
 | 
			
		||||
        use TermSplit::*;
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            (Vertical {
 | 
			
		||||
                top: Term {
 | 
			
		||||
                    frame: TermFrame(1)
 | 
			
		||||
                }
 | 
			
		||||
                .into(),
 | 
			
		||||
                bottom: Horizontal {
 | 
			
		||||
                    left: Term {
 | 
			
		||||
                        frame: TermFrame(1)
 | 
			
		||||
                    }
 | 
			
		||||
                    .into(),
 | 
			
		||||
                    right: Term {
 | 
			
		||||
                        frame: TermFrame(3)
 | 
			
		||||
                    }
 | 
			
		||||
                    .into(),
 | 
			
		||||
                }
 | 
			
		||||
                .into()
 | 
			
		||||
            })
 | 
			
		||||
            .validate(),
 | 
			
		||||
            Err("Attempt to create layout that duplicates reference to: Terminal 1".to_owned())
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            (Vertical {
 | 
			
		||||
                top: Term {
 | 
			
		||||
                    frame: TermFrame(42)
 | 
			
		||||
                }
 | 
			
		||||
                .into(),
 | 
			
		||||
                bottom: Horizontal {
 | 
			
		||||
                    left: Term {
 | 
			
		||||
                        frame: TermFrame(1)
 | 
			
		||||
                    }
 | 
			
		||||
                    .into(),
 | 
			
		||||
                    right: Term {
 | 
			
		||||
                        frame: TermFrame(42)
 | 
			
		||||
                    }
 | 
			
		||||
                    .into(),
 | 
			
		||||
                }
 | 
			
		||||
                .into()
 | 
			
		||||
            })
 | 
			
		||||
            .validate(),
 | 
			
		||||
            Err("Attempt to create layout that duplicates reference to: Terminal 42".to_owned())
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn modify_at_pathstr_works() {
 | 
			
		||||
        use TermSplit::*;
 | 
			
		||||
        let mut t = Term {
 | 
			
		||||
            frame: TermFrame(1),
 | 
			
		||||
        };
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            t.modify_at_pathstr("", |v| {
 | 
			
		||||
                *v = Term {
 | 
			
		||||
                    frame: TermFrame(2),
 | 
			
		||||
                };
 | 
			
		||||
                Ok(())
 | 
			
		||||
            }),
 | 
			
		||||
            Ok(())
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            t,
 | 
			
		||||
            Term {
 | 
			
		||||
                frame: TermFrame(2)
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            t.modify_at_pathstr("tlr", |v| {
 | 
			
		||||
                *v = Term {
 | 
			
		||||
                    frame: TermFrame(2),
 | 
			
		||||
                };
 | 
			
		||||
                Ok(())
 | 
			
		||||
            }),
 | 
			
		||||
            Err("In split path, found trailing junk tlr after addressing terminal".to_owned())
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let mut t = Vertical {
 | 
			
		||||
            top: Horizontal {
 | 
			
		||||
                left: Horizontal {
 | 
			
		||||
                    left: Term {
 | 
			
		||||
                        frame: TermFrame(42),
 | 
			
		||||
                    }
 | 
			
		||||
                    .into(),
 | 
			
		||||
                    right: Term {
 | 
			
		||||
                        frame: TermFrame(64),
 | 
			
		||||
                    }
 | 
			
		||||
                    .into(),
 | 
			
		||||
                }
 | 
			
		||||
                .into(),
 | 
			
		||||
                right: Term {
 | 
			
		||||
                    frame: TermFrame(42),
 | 
			
		||||
                }
 | 
			
		||||
                .into(),
 | 
			
		||||
            }
 | 
			
		||||
            .into(),
 | 
			
		||||
            bottom: Vertical {
 | 
			
		||||
                top: Term {
 | 
			
		||||
                    frame: TermFrame(43),
 | 
			
		||||
                }
 | 
			
		||||
                .into(),
 | 
			
		||||
                bottom: Term {
 | 
			
		||||
                    frame: TermFrame(44),
 | 
			
		||||
                }
 | 
			
		||||
                .into(),
 | 
			
		||||
            }
 | 
			
		||||
            .into(),
 | 
			
		||||
        };
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            t.modify_at_pathstr("tlr", |v| {
 | 
			
		||||
                *v = Term {
 | 
			
		||||
                    frame: TermFrame(2),
 | 
			
		||||
                };
 | 
			
		||||
                Ok(())
 | 
			
		||||
            }),
 | 
			
		||||
            Ok(())
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            t.modify_at_pathstr("bb", |v| {
 | 
			
		||||
                *v = Term {
 | 
			
		||||
                    frame: TermFrame(3),
 | 
			
		||||
                };
 | 
			
		||||
                Ok(())
 | 
			
		||||
            }),
 | 
			
		||||
            Ok(())
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            t,
 | 
			
		||||
            Vertical {
 | 
			
		||||
                top: Horizontal {
 | 
			
		||||
                    left: Horizontal {
 | 
			
		||||
                        left: Term {
 | 
			
		||||
                            frame: TermFrame(42),
 | 
			
		||||
                        }
 | 
			
		||||
                        .into(),
 | 
			
		||||
                        right: Term {
 | 
			
		||||
                            frame: TermFrame(2),
 | 
			
		||||
                        }
 | 
			
		||||
                        .into(),
 | 
			
		||||
                    }
 | 
			
		||||
                    .into(),
 | 
			
		||||
                    right: Term {
 | 
			
		||||
                        frame: TermFrame(42),
 | 
			
		||||
                    }
 | 
			
		||||
                    .into(),
 | 
			
		||||
                }
 | 
			
		||||
                .into(),
 | 
			
		||||
                bottom: Vertical {
 | 
			
		||||
                    top: Term {
 | 
			
		||||
                        frame: TermFrame(43),
 | 
			
		||||
                    }
 | 
			
		||||
                    .into(),
 | 
			
		||||
                    bottom: Term {
 | 
			
		||||
                        frame: TermFrame(3),
 | 
			
		||||
                    }
 | 
			
		||||
                    .into(),
 | 
			
		||||
                }
 | 
			
		||||
                .into(),
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -7,7 +7,8 @@ use yew::prelude::*;
 | 
			
		||||
use crate::{
 | 
			
		||||
    command_handler::command_handler,
 | 
			
		||||
    lineengine::line::{Readline, ReadlineEvent},
 | 
			
		||||
    GlobalCell,
 | 
			
		||||
    term_split::TermSplit,
 | 
			
		||||
    GlobalCell, PanelDirection, SplitPanel,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
@ -64,7 +65,7 @@ extern "C" {
 | 
			
		||||
    fn fit(this: &FitAddon);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Eq, Ord, Hash, PartialEq, PartialOrd, Clone)]
 | 
			
		||||
#[derive(Eq, Ord, Hash, PartialEq, PartialOrd, Clone, Debug)]
 | 
			
		||||
pub struct TermFrame(pub u64);
 | 
			
		||||
 | 
			
		||||
#[derive(Properties)]
 | 
			
		||||
@ -212,6 +213,39 @@ pub fn term_view(props: &TermViewProps) -> Html {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Properties, PartialEq)]
 | 
			
		||||
pub struct TermViewTreeProps {
 | 
			
		||||
    pub global: GlobalCell,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[function_component(TermViewTree)]
 | 
			
		||||
pub fn term_view_tree(props: &TermViewTreeProps) -> Html {
 | 
			
		||||
    fn mk_term_view_tree(global: &GlobalCell, split: &TermSplit) -> Html {
 | 
			
		||||
        use TermSplit::*;
 | 
			
		||||
        match split {
 | 
			
		||||
            Term { frame } => html! {
 | 
			
		||||
                <TermView global={global.clone()} terminal={frame.clone()}/>
 | 
			
		||||
            },
 | 
			
		||||
            Horizontal { left, right } => html! {
 | 
			
		||||
                <SplitPanel
 | 
			
		||||
                    direction={PanelDirection::Horizontal}
 | 
			
		||||
                    first={mk_term_view_tree(global, left)}
 | 
			
		||||
                    second={mk_term_view_tree(global, right)}
 | 
			
		||||
                />
 | 
			
		||||
            },
 | 
			
		||||
            Vertical { top, bottom } => html! {
 | 
			
		||||
                <SplitPanel
 | 
			
		||||
                    direction={PanelDirection::Vertical}
 | 
			
		||||
                    first={mk_term_view_tree(global, top)}
 | 
			
		||||
                    second={mk_term_view_tree(global, bottom)}
 | 
			
		||||
                />
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mk_term_view_tree(&props.global, &props.global.term_splits.borrow())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn echo_to_term_frame(
 | 
			
		||||
    global: &GlobalCell,
 | 
			
		||||
    frame_id: &TermFrame,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user