getting towards terminal integration
This commit is contained in:
parent
4c00a633af
commit
24710414bd
10 changed files with 417 additions and 1 deletions
|
@ -1,6 +1,7 @@
|
|||
use crate::{platform, theme::*, Filename, Layout, Mode};
|
||||
use std::sync::Arc;
|
||||
use zoon::*;
|
||||
use crate::term::TERM_OPEN;
|
||||
|
||||
pub struct HeaderPanel {
|
||||
hierarchy: Mutable<Option<Arc<wellen::Hierarchy>>>,
|
||||
|
@ -37,6 +38,7 @@ impl HeaderPanel {
|
|||
.item(self.load_button())
|
||||
.item(self.layout_switcher())
|
||||
.item(self.mode_switcher())
|
||||
.item(self.open_terminal())
|
||||
.item(self.open_konata_file()),
|
||||
)
|
||||
}
|
||||
|
@ -212,4 +214,26 @@ impl HeaderPanel {
|
|||
.on_hovered_change(move |is_hovered| hovered.set_neq(is_hovered))
|
||||
.on_press(move || Task::start(platform::open_konata_file()))
|
||||
}
|
||||
|
||||
fn open_terminal(&self) -> impl Element {
|
||||
let (hovered, hovered_signal) = Mutable::new_and_signal(false);
|
||||
Button::new()
|
||||
.s(Padding::new().x(20).y(10))
|
||||
.s(Background::new().color_signal(
|
||||
hovered_signal.map_bool(|| COLOR_MEDIUM_SLATE_BLUE, || COLOR_SLATE_BLUE),
|
||||
))
|
||||
.s(Align::new().left())
|
||||
.s(RoundedCorners::all(15))
|
||||
.label(
|
||||
El::new()
|
||||
.s(Font::new().no_wrap())
|
||||
.child("Open Terminal"),
|
||||
)
|
||||
.on_hovered_change(move |is_hovered| hovered.set_neq(is_hovered))
|
||||
.on_press(move || {
|
||||
let term_open = TERM_OPEN.get();
|
||||
TERM_OPEN.set(!term_open);
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use shared::DiagramConnectorMessage;
|
||||
use term::TERM_OPEN;
|
||||
use std::{mem, sync::Arc};
|
||||
use zoon::*;
|
||||
|
||||
|
@ -23,6 +24,8 @@ use command_panel::CommandPanel;
|
|||
pub mod theme;
|
||||
use theme::*;
|
||||
|
||||
pub mod term;
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
enum Layout {
|
||||
Tree,
|
||||
|
@ -181,4 +184,15 @@ fn root() -> impl Element {
|
|||
}
|
||||
})))
|
||||
.item(CommandPanel::new())
|
||||
.item_signal(
|
||||
TERM_OPEN.signal_cloned().map(
|
||||
|term_open| {
|
||||
match term_open {
|
||||
true => {El::new().child("Terminal")}
|
||||
false => {El::new().child("")}
|
||||
}
|
||||
}
|
||||
)
|
||||
// El::new()
|
||||
)
|
||||
}
|
||||
|
|
148
frontend/src/term.rs
Normal file
148
frontend/src/term.rs
Normal file
|
@ -0,0 +1,148 @@
|
|||
use std::ops::Index;
|
||||
|
||||
use chrono::format;
|
||||
use zoon::*;
|
||||
use zoon::{println, eprintln, *};
|
||||
use shared::term::{TerminalDownMsg, TerminalScreen, TerminalUpMsg};
|
||||
|
||||
// use tokio::time::timeout;
|
||||
pub static TERM_OPEN: Lazy<Mutable<bool>> = Lazy::new(|| {false.into()});
|
||||
|
||||
static TERMINAL_STATE: Lazy<Mutable<TerminalDownMsg>> =
|
||||
Lazy::new(|| {
|
||||
Mutable::new(TerminalDownMsg::TermNotStarted)
|
||||
});
|
||||
|
||||
// static CONNECTION: Lazy<Connection<UpMsg, DownMsg>> = Lazy::new(|| {
|
||||
// Connection::new(
|
||||
// |down_msg, _| {
|
||||
// match down_msg {
|
||||
// DownMsg::TerminalDownMsg(terminal_msg) => {
|
||||
// TERMINAL_STATE.set(terminal_msg);
|
||||
// }
|
||||
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
// });
|
||||
|
||||
pub fn root() -> impl Element {
|
||||
term_request();
|
||||
let terminal =
|
||||
El::new()
|
||||
.s(Width::fill())
|
||||
.s(Height::fill())
|
||||
.s(Font::new().family([
|
||||
FontFamily::new("Lucida Console"),
|
||||
FontFamily::new("Courier"),
|
||||
FontFamily::new("monospace")
|
||||
]))
|
||||
.update_raw_el(|raw_el| {
|
||||
raw_el.global_event_handler(|event: events::KeyDown| {
|
||||
println!("Pressed key: {}", &event.key());
|
||||
send_char(
|
||||
(&event).key().as_str(),
|
||||
(&event).ctrl_key(),
|
||||
);
|
||||
})
|
||||
})
|
||||
.child_signal(TERMINAL_STATE.signal_cloned().map(
|
||||
|down_msg| {
|
||||
match down_msg {
|
||||
TerminalDownMsg::FullTermUpdate(term) => {
|
||||
make_grid_with_newlines(&term)
|
||||
},
|
||||
TerminalDownMsg::TermNotStarted => {
|
||||
"Term not yet started!".to_string()
|
||||
},
|
||||
TerminalDownMsg::BackendTermStartFailure(msg) => {
|
||||
format!("Error: BackendTermStartFailure: {}", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
;
|
||||
let root = Column::new()
|
||||
.s(Width::fill())
|
||||
.s(Height::fill())
|
||||
.s(Align::new().top())
|
||||
.item(terminal);
|
||||
root
|
||||
}
|
||||
|
||||
// TODO : fill this out
|
||||
fn term_request() {
|
||||
}
|
||||
|
||||
fn send_char(
|
||||
s : &str,
|
||||
has_control : bool,
|
||||
) {
|
||||
match process_str(s, has_control) {
|
||||
// TODO : fill this out
|
||||
Some(c) => {
|
||||
eprintln!("Sending char: {}", c);
|
||||
}
|
||||
None => {eprintln!("Not processing: {}", s)}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn make_grid_with_newlines(term : &TerminalScreen) -> String {
|
||||
let mut formatted = String::new();
|
||||
for (i, c) in term.content.chars().enumerate() {
|
||||
formatted.push(c);
|
||||
if (i + 1) % term.cols == 0 {
|
||||
formatted.push('\n');
|
||||
}
|
||||
}
|
||||
formatted
|
||||
}
|
||||
|
||||
fn process_str(s: &str, has_ctrl : bool) -> Option<char> {
|
||||
match s {
|
||||
"Enter" => {return Some('\n');}
|
||||
"Escape" => {return Some('\x1B');}
|
||||
"Backspace" => {return Some('\x08');}
|
||||
"ArrowUp" => {return Some('\x10');}
|
||||
"ArrowDown" => {return Some('\x0E');}
|
||||
"ArrowLeft" => {return Some('\x02');}
|
||||
"ArrowRight" => {return Some('\x06');}
|
||||
_ => {}
|
||||
}
|
||||
// Check if the string has exactly one character
|
||||
if s.chars().count() == 1 {
|
||||
// Safe unwrap because we know the length is 1
|
||||
let c = s.chars().next().unwrap();
|
||||
let c = process_for_ctrl_char(c, has_ctrl);
|
||||
return Some(c);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn is_lowercase_alpha(c: char) -> bool {
|
||||
char_is_between_inclusive(c, 'a', 'z')
|
||||
}
|
||||
|
||||
fn process_for_ctrl_char(c: char, has_ctrl : bool) -> char {
|
||||
let mut final_ctrl_char = c;
|
||||
if has_ctrl {
|
||||
if is_lowercase_alpha(c) {
|
||||
let c_u8 = (c as u8);
|
||||
let ctrl_char_u8 = c_u8 - 96;
|
||||
final_ctrl_char = (ctrl_char_u8 as char);
|
||||
} else if char_is_between_inclusive(c, '[', '_') {
|
||||
let c_u8 = (c as u8);
|
||||
let ctrl_char_u8 = c_u8 - 90;
|
||||
final_ctrl_char = (ctrl_char_u8 as char);
|
||||
}
|
||||
|
||||
}
|
||||
return final_ctrl_char
|
||||
}
|
||||
|
||||
fn char_is_between_inclusive(c : char, lo_char : char, hi_char : char) -> bool {
|
||||
c >= lo_char && c <= hi_char
|
||||
}
|
Reference in a new issue