Added the set_selectable plugin API function
This commit is contained in:
parent
7e308515e5
commit
efcd36a52c
11 changed files with 170 additions and 63 deletions
|
|
@ -166,6 +166,7 @@ pub enum ScreenContext {
|
|||
ClearScroll,
|
||||
CloseFocusedPane,
|
||||
ToggleActiveTerminalFullscreen,
|
||||
SetSelectable,
|
||||
ClosePane,
|
||||
ApplyLayout,
|
||||
NewTab,
|
||||
|
|
@ -200,6 +201,7 @@ impl From<&ScreenInstruction> for ScreenContext {
|
|||
ScreenInstruction::ToggleActiveTerminalFullscreen => {
|
||||
ScreenContext::ToggleActiveTerminalFullscreen
|
||||
}
|
||||
ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable,
|
||||
ScreenInstruction::ClosePane(_) => ScreenContext::ClosePane,
|
||||
ScreenInstruction::ApplyLayout(_) => ScreenContext::ApplyLayout,
|
||||
ScreenInstruction::NewTab(_) => ScreenContext::NewTab,
|
||||
|
|
@ -244,6 +246,7 @@ pub enum PluginContext {
|
|||
Load,
|
||||
Draw,
|
||||
Input,
|
||||
GlobalInput,
|
||||
Unload,
|
||||
Quit,
|
||||
}
|
||||
|
|
@ -254,6 +257,7 @@ impl From<&PluginInstruction> for PluginContext {
|
|||
PluginInstruction::Load(..) => PluginContext::Load,
|
||||
PluginInstruction::Draw(..) => PluginContext::Draw,
|
||||
PluginInstruction::Input(..) => PluginContext::Input,
|
||||
PluginInstruction::GlobalInput(_) => PluginContext::GlobalInput,
|
||||
PluginInstruction::Unload(_) => PluginContext::Unload,
|
||||
PluginInstruction::Quit => PluginContext::Quit,
|
||||
}
|
||||
|
|
|
|||
21
src/input.rs
21
src/input.rs
|
|
@ -1,9 +1,9 @@
|
|||
/// Module for handling input
|
||||
use crate::errors::ContextType;
|
||||
use crate::os_input_output::OsApi;
|
||||
use crate::pty_bus::PtyInstruction;
|
||||
use crate::screen::ScreenInstruction;
|
||||
use crate::CommandIsExecuting;
|
||||
use crate::{errors::ContextType, wasm_vm::PluginInstruction};
|
||||
use crate::{AppInstruction, SenderWithContext, OPENCALLS};
|
||||
|
||||
struct InputHandler {
|
||||
|
|
@ -12,6 +12,7 @@ struct InputHandler {
|
|||
command_is_executing: CommandIsExecuting,
|
||||
send_screen_instructions: SenderWithContext<ScreenInstruction>,
|
||||
send_pty_instructions: SenderWithContext<PtyInstruction>,
|
||||
send_plugin_instructions: SenderWithContext<PluginInstruction>,
|
||||
send_app_instructions: SenderWithContext<AppInstruction>,
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ impl InputHandler {
|
|||
command_is_executing: CommandIsExecuting,
|
||||
send_screen_instructions: SenderWithContext<ScreenInstruction>,
|
||||
send_pty_instructions: SenderWithContext<PtyInstruction>,
|
||||
send_plugin_instructions: SenderWithContext<PluginInstruction>,
|
||||
send_app_instructions: SenderWithContext<AppInstruction>,
|
||||
) -> Self {
|
||||
InputHandler {
|
||||
|
|
@ -29,6 +31,7 @@ impl InputHandler {
|
|||
command_is_executing,
|
||||
send_screen_instructions,
|
||||
send_pty_instructions,
|
||||
send_plugin_instructions,
|
||||
send_app_instructions,
|
||||
}
|
||||
}
|
||||
|
|
@ -38,6 +41,7 @@ impl InputHandler {
|
|||
let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow());
|
||||
err_ctx.add_call(ContextType::StdinHandler);
|
||||
self.send_pty_instructions.update(err_ctx);
|
||||
self.send_plugin_instructions.update(err_ctx);
|
||||
self.send_app_instructions.update(err_ctx);
|
||||
self.send_screen_instructions.update(err_ctx);
|
||||
loop {
|
||||
|
|
@ -59,6 +63,11 @@ impl InputHandler {
|
|||
|
||||
loop {
|
||||
let stdin_buffer = self.os_input.read_from_stdin();
|
||||
#[cfg(not(test))] // Absolutely zero clue why this breaks *all* of the tests
|
||||
drop(
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::GlobalInput(stdin_buffer.clone())),
|
||||
);
|
||||
match stdin_buffer.as_slice() {
|
||||
[7] => {
|
||||
// ctrl-g
|
||||
|
|
@ -88,6 +97,11 @@ impl InputHandler {
|
|||
|
||||
loop {
|
||||
let stdin_buffer = self.os_input.read_from_stdin();
|
||||
#[cfg(not(test))] // Absolutely zero clue why this breaks *all* of the tests
|
||||
drop(
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::GlobalInput(stdin_buffer.clone())),
|
||||
);
|
||||
// uncomment this to print the entered character to a log file (/tmp/mosaic/mosaic-log.txt) for debugging
|
||||
// debug_log_to_file(format!("buffer {:?}", stdin_buffer));
|
||||
|
||||
|
|
@ -267,6 +281,9 @@ impl InputHandler {
|
|||
self.send_pty_instructions
|
||||
.send(PtyInstruction::Quit)
|
||||
.unwrap();
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Quit)
|
||||
.unwrap();
|
||||
self.send_app_instructions
|
||||
.send(AppInstruction::Exit)
|
||||
.unwrap();
|
||||
|
|
@ -297,6 +314,7 @@ pub fn input_loop(
|
|||
command_is_executing: CommandIsExecuting,
|
||||
send_screen_instructions: SenderWithContext<ScreenInstruction>,
|
||||
send_pty_instructions: SenderWithContext<PtyInstruction>,
|
||||
send_plugin_instructions: SenderWithContext<PluginInstruction>,
|
||||
send_app_instructions: SenderWithContext<AppInstruction>,
|
||||
) {
|
||||
let _handler = InputHandler::new(
|
||||
|
|
@ -304,6 +322,7 @@ pub fn input_loop(
|
|||
command_is_executing,
|
||||
send_screen_instructions,
|
||||
send_pty_instructions,
|
||||
send_plugin_instructions,
|
||||
send_app_instructions,
|
||||
)
|
||||
.get_input();
|
||||
|
|
|
|||
47
src/main.rs
47
src/main.rs
|
|
@ -355,6 +355,14 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
screen.get_active_tab_mut().unwrap().close_focused_pane();
|
||||
screen.render();
|
||||
}
|
||||
ScreenInstruction::SetSelectable(id, selectable) => {
|
||||
screen
|
||||
.get_active_tab_mut()
|
||||
.unwrap()
|
||||
.set_pane_selectable(id, selectable);
|
||||
// FIXME: Is this needed?
|
||||
screen.render();
|
||||
}
|
||||
ScreenInstruction::ClosePane(id) => {
|
||||
screen.get_active_tab_mut().unwrap().close_pane(id);
|
||||
screen.render();
|
||||
|
|
@ -430,7 +438,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
let wasi = wasi_env.import_object(&module).unwrap();
|
||||
|
||||
let plugin_env = PluginEnv {
|
||||
plugin_id,
|
||||
send_pty_instructions: send_pty_instructions.clone(),
|
||||
send_screen_instructions: send_screen_instructions.clone(),
|
||||
wasi_env,
|
||||
};
|
||||
|
||||
|
|
@ -457,15 +467,29 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
|
||||
buf_tx.send(wasi_stdout(&plugin_env.wasi_env)).unwrap();
|
||||
}
|
||||
// FIXME: Deduplicate this with the callback below!
|
||||
PluginInstruction::Input(pid, input_bytes) => {
|
||||
let (instance, plugin_env) = plugin_map.get(&pid).unwrap();
|
||||
|
||||
let handle_key =
|
||||
instance.exports.get_function("handle_key").unwrap();
|
||||
for key in input_bytes.keys() {
|
||||
if let Ok(key) = key {
|
||||
wasi_write_string(
|
||||
&plugin_env.wasi_env,
|
||||
&serde_json::to_string(&key).unwrap(),
|
||||
);
|
||||
handle_key.call(&[]).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
drop(send_screen_instructions.send(ScreenInstruction::Render));
|
||||
}
|
||||
PluginInstruction::GlobalInput(input_bytes) => {
|
||||
// FIXME: Set up an event subscription system, and timed callbacks
|
||||
for (&id, (instance, plugin_env)) in &plugin_map {
|
||||
let handler = if PaneId::Plugin(id) == pid {
|
||||
"handle_key"
|
||||
} else {
|
||||
"handle_global_key"
|
||||
};
|
||||
let handler = instance.exports.get_function(handler).unwrap();
|
||||
for (instance, plugin_env) in plugin_map.values() {
|
||||
let handler =
|
||||
instance.exports.get_function("handle_global_key").unwrap();
|
||||
for key in input_bytes.keys() {
|
||||
if let Ok(key) = key {
|
||||
wasi_write_string(
|
||||
|
|
@ -477,9 +501,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
}
|
||||
}
|
||||
|
||||
send_screen_instructions
|
||||
.send(ScreenInstruction::Render)
|
||||
.unwrap();
|
||||
drop(send_screen_instructions.send(ScreenInstruction::Render));
|
||||
}
|
||||
PluginInstruction::Unload(pid) => drop(plugin_map.remove(&pid)),
|
||||
PluginInstruction::Quit => break,
|
||||
|
|
@ -556,6 +578,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
.spawn({
|
||||
let send_screen_instructions = send_screen_instructions.clone();
|
||||
let send_pty_instructions = send_pty_instructions.clone();
|
||||
let send_plugin_instructions = send_plugin_instructions.clone();
|
||||
let os_input = os_input.clone();
|
||||
move || {
|
||||
input_loop(
|
||||
|
|
@ -563,6 +586,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
command_is_executing,
|
||||
send_screen_instructions,
|
||||
send_pty_instructions,
|
||||
send_plugin_instructions,
|
||||
send_app_instructions,
|
||||
)
|
||||
}
|
||||
|
|
@ -581,14 +605,12 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
AppInstruction::Exit => {
|
||||
let _ = send_screen_instructions.send(ScreenInstruction::Quit);
|
||||
let _ = send_pty_instructions.send(PtyInstruction::Quit);
|
||||
|
||||
let _ = send_plugin_instructions.send(PluginInstruction::Quit);
|
||||
break;
|
||||
}
|
||||
AppInstruction::Error(backtrace) => {
|
||||
let _ = send_screen_instructions.send(ScreenInstruction::Quit);
|
||||
let _ = send_pty_instructions.send(PtyInstruction::Quit);
|
||||
|
||||
let _ = send_plugin_instructions.send(PluginInstruction::Quit);
|
||||
os_input.unset_raw_mode(0);
|
||||
let goto_start_of_last_line = format!("\u{1b}[{};{}H", full_screen_ws.rows, 1);
|
||||
|
|
@ -608,6 +630,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
for thread_handler in active_threads {
|
||||
thread_handler.join().unwrap();
|
||||
}
|
||||
|
||||
// cleanup();
|
||||
let reset_style = "\u{1b}[m";
|
||||
let show_cursor = "\u{1b}[?25h";
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use crate::panes::{PaneId, PositionAndSize};
|
|||
pub struct PluginPane {
|
||||
pub pid: u32,
|
||||
pub should_render: bool,
|
||||
pub selectable: bool,
|
||||
pub position_and_size: PositionAndSize,
|
||||
pub position_and_size_override: Option<PositionAndSize>,
|
||||
pub send_plugin_instructions: SenderWithContext<PluginInstruction>,
|
||||
|
|
@ -23,6 +24,7 @@ impl PluginPane {
|
|||
Self {
|
||||
pid,
|
||||
should_render: true,
|
||||
selectable: true,
|
||||
position_and_size,
|
||||
position_and_size_override: None,
|
||||
send_plugin_instructions,
|
||||
|
|
@ -92,6 +94,12 @@ impl Pane for PluginPane {
|
|||
fn set_should_render(&mut self, should_render: bool) {
|
||||
self.should_render = should_render;
|
||||
}
|
||||
fn selectable(&self) -> bool {
|
||||
self.selectable
|
||||
}
|
||||
fn set_selectable(&mut self, selectable: bool) {
|
||||
self.selectable = selectable;
|
||||
}
|
||||
fn render(&mut self) -> Option<String> {
|
||||
// if self.should_render {
|
||||
if true {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ pub struct TerminalPane {
|
|||
pub pid: RawFd,
|
||||
pub scroll: Scroll,
|
||||
pub should_render: bool,
|
||||
pub selectable: bool,
|
||||
pub position_and_size: PositionAndSize,
|
||||
pub position_and_size_override: Option<PositionAndSize>,
|
||||
pub cursor_key_mode: bool, // DECCKM - when set, cursor keys should send ANSI direction codes (eg. "OD") instead of the arrow keys (eg. "[D")
|
||||
|
|
@ -165,6 +166,12 @@ impl Pane for TerminalPane {
|
|||
fn set_should_render(&mut self, should_render: bool) {
|
||||
self.should_render = should_render;
|
||||
}
|
||||
fn selectable(&self) -> bool {
|
||||
self.selectable
|
||||
}
|
||||
fn set_selectable(&mut self, selectable: bool) {
|
||||
self.selectable = selectable;
|
||||
}
|
||||
fn render(&mut self) -> Option<String> {
|
||||
// if self.should_render {
|
||||
if true {
|
||||
|
|
@ -274,6 +281,7 @@ impl TerminalPane {
|
|||
pid,
|
||||
scroll,
|
||||
should_render: true,
|
||||
selectable: true,
|
||||
pending_styles,
|
||||
position_and_size,
|
||||
position_and_size_override: None,
|
||||
|
|
|
|||
|
|
@ -299,13 +299,15 @@ impl PtyBus {
|
|||
let child_pid = self.id_to_child_pid.get(&id).unwrap();
|
||||
self.os_input.kill(*child_pid).unwrap();
|
||||
}
|
||||
PaneId::Plugin(pid) => self
|
||||
.send_plugin_instructions
|
||||
.send(PluginInstruction::Unload(pid))
|
||||
.unwrap(),
|
||||
PaneId::Plugin(pid) => drop(
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Unload(pid)),
|
||||
),
|
||||
}
|
||||
}
|
||||
pub fn close_tab(&mut self, ids: Vec<PaneId>) {
|
||||
ids.iter().for_each(|&id| self.close_pane(id));
|
||||
ids.iter().for_each(|&id| {
|
||||
self.close_pane(id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ pub enum ScreenInstruction {
|
|||
ClearScroll,
|
||||
CloseFocusedPane,
|
||||
ToggleActiveTerminalFullscreen,
|
||||
SetSelectable(PaneId, bool),
|
||||
ClosePane(PaneId),
|
||||
ApplyLayout((Layout, Vec<RawFd>)),
|
||||
NewTab(RawFd),
|
||||
|
|
@ -138,7 +139,7 @@ impl Screen {
|
|||
if self.tabs.len() > 1 {
|
||||
self.switch_tab_prev();
|
||||
}
|
||||
let mut active_tab = self.tabs.remove(&active_tab_index).unwrap();
|
||||
let active_tab = self.tabs.remove(&active_tab_index).unwrap();
|
||||
let pane_ids = active_tab.get_pane_ids();
|
||||
self.send_pty_instructions
|
||||
.send(PtyInstruction::CloseTab(pane_ids))
|
||||
|
|
|
|||
105
src/tab.rs
105
src/tab.rs
|
|
@ -66,6 +66,7 @@ pub struct Tab {
|
|||
pub send_app_instructions: SenderWithContext<AppInstruction>,
|
||||
}
|
||||
|
||||
// FIXME: Use a struct that has a pane_type enum, to reduce all of the duplication
|
||||
pub trait Pane {
|
||||
fn x(&self) -> usize;
|
||||
fn y(&self) -> usize;
|
||||
|
|
@ -81,6 +82,8 @@ pub trait Pane {
|
|||
fn position_and_size_override(&self) -> Option<PositionAndSize>;
|
||||
fn should_render(&self) -> bool;
|
||||
fn set_should_render(&mut self, should_render: bool);
|
||||
fn selectable(&self) -> bool;
|
||||
fn set_selectable(&mut self, selectable: bool);
|
||||
fn render(&mut self) -> Option<String>;
|
||||
fn pid(&self) -> PaneId;
|
||||
fn reduce_height_down(&mut self, count: usize);
|
||||
|
|
@ -473,23 +476,23 @@ impl Tab {
|
|||
}
|
||||
}
|
||||
pub fn write_to_active_terminal(&mut self, input_bytes: Vec<u8>) {
|
||||
let pid = self.get_active_pane_id();
|
||||
|
||||
if let Some(pid) = pid {
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Input(pid, input_bytes.clone()))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if let Some(PaneId::Terminal(active_terminal_id)) = pid {
|
||||
let active_terminal = self.get_active_pane().unwrap();
|
||||
let mut adjusted_input = active_terminal.adjust_input_to_terminal(input_bytes);
|
||||
self.os_api
|
||||
.write_to_tty_stdin(active_terminal_id, &mut adjusted_input)
|
||||
.expect("failed to write to terminal");
|
||||
self.os_api
|
||||
.tcdrain(active_terminal_id)
|
||||
.expect("failed to drain terminal");
|
||||
match self.get_active_pane_id() {
|
||||
Some(PaneId::Terminal(active_terminal_id)) => {
|
||||
let active_terminal = self.get_active_pane().unwrap();
|
||||
let mut adjusted_input = active_terminal.adjust_input_to_terminal(input_bytes);
|
||||
self.os_api
|
||||
.write_to_tty_stdin(active_terminal_id, &mut adjusted_input)
|
||||
.expect("failed to write to terminal");
|
||||
self.os_api
|
||||
.tcdrain(active_terminal_id)
|
||||
.expect("failed to drain terminal");
|
||||
}
|
||||
Some(PaneId::Plugin(pid)) => {
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Input(pid, input_bytes))
|
||||
.unwrap();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
pub fn get_active_terminal_cursor_position(&self) -> Option<(usize, usize)> {
|
||||
|
|
@ -618,10 +621,24 @@ impl Tab {
|
|||
fn get_panes(&self) -> impl Iterator<Item = (&PaneId, &Box<dyn Pane>)> {
|
||||
self.panes.iter()
|
||||
}
|
||||
// FIXME: This is some shameful duplication...
|
||||
fn get_selectable_panes(&self) -> impl Iterator<Item = (&PaneId, &Box<dyn Pane>)> {
|
||||
self.panes.iter().filter(|(_, p)| p.selectable())
|
||||
}
|
||||
fn has_panes(&self) -> bool {
|
||||
let mut all_terminals = self.get_panes();
|
||||
all_terminals.next().is_some()
|
||||
}
|
||||
fn has_selectable_panes(&self) -> bool {
|
||||
let mut all_terminals = self.get_selectable_panes();
|
||||
all_terminals.next().is_some()
|
||||
}
|
||||
fn next_active_pane(&self, panes: Vec<PaneId>) -> Option<PaneId> {
|
||||
panes
|
||||
.into_iter()
|
||||
.rev()
|
||||
.find(|pid| self.panes.get(pid).unwrap().selectable())
|
||||
}
|
||||
fn pane_ids_directly_left_of(&self, id: &PaneId) -> Option<Vec<PaneId>> {
|
||||
let mut ids = vec![];
|
||||
let terminal_to_check = self.panes.get(id).unwrap();
|
||||
|
|
@ -1421,14 +1438,14 @@ impl Tab {
|
|||
}
|
||||
}
|
||||
pub fn move_focus(&mut self) {
|
||||
if !self.has_panes() {
|
||||
if !self.has_selectable_panes() {
|
||||
return;
|
||||
}
|
||||
if self.fullscreen_is_active {
|
||||
return;
|
||||
}
|
||||
let active_terminal_id = self.get_active_pane_id().unwrap();
|
||||
let terminal_ids: Vec<PaneId> = self.get_panes().map(|(&pid, _)| pid).collect(); // TODO: better, no allocations
|
||||
let terminal_ids: Vec<PaneId> = self.get_selectable_panes().map(|(&pid, _)| pid).collect(); // TODO: better, no allocations
|
||||
let first_terminal = terminal_ids.get(0).unwrap();
|
||||
let active_terminal_id_position = terminal_ids
|
||||
.iter()
|
||||
|
|
@ -1442,7 +1459,7 @@ impl Tab {
|
|||
self.render();
|
||||
}
|
||||
pub fn move_focus_left(&mut self) {
|
||||
if !self.has_panes() {
|
||||
if !self.has_selectable_panes() {
|
||||
return;
|
||||
}
|
||||
if self.fullscreen_is_active {
|
||||
|
|
@ -1450,7 +1467,7 @@ impl Tab {
|
|||
}
|
||||
let active_terminal = self.get_active_pane();
|
||||
if let Some(active) = active_terminal {
|
||||
let terminals = self.get_panes();
|
||||
let terminals = self.get_selectable_panes();
|
||||
let next_index = terminals
|
||||
.enumerate()
|
||||
.filter(|(_, (_, c))| {
|
||||
|
|
@ -1472,7 +1489,7 @@ impl Tab {
|
|||
self.render();
|
||||
}
|
||||
pub fn move_focus_down(&mut self) {
|
||||
if !self.has_panes() {
|
||||
if !self.has_selectable_panes() {
|
||||
return;
|
||||
}
|
||||
if self.fullscreen_is_active {
|
||||
|
|
@ -1480,7 +1497,7 @@ impl Tab {
|
|||
}
|
||||
let active_terminal = self.get_active_pane();
|
||||
if let Some(active) = active_terminal {
|
||||
let terminals = self.get_panes();
|
||||
let terminals = self.get_selectable_panes();
|
||||
let next_index = terminals
|
||||
.enumerate()
|
||||
.filter(|(_, (_, c))| {
|
||||
|
|
@ -1502,7 +1519,7 @@ impl Tab {
|
|||
self.render();
|
||||
}
|
||||
pub fn move_focus_up(&mut self) {
|
||||
if !self.has_panes() {
|
||||
if !self.has_selectable_panes() {
|
||||
return;
|
||||
}
|
||||
if self.fullscreen_is_active {
|
||||
|
|
@ -1510,7 +1527,7 @@ impl Tab {
|
|||
}
|
||||
let active_terminal = self.get_active_pane();
|
||||
if let Some(active) = active_terminal {
|
||||
let terminals = self.get_panes();
|
||||
let terminals = self.get_selectable_panes();
|
||||
let next_index = terminals
|
||||
.enumerate()
|
||||
.filter(|(_, (_, c))| {
|
||||
|
|
@ -1532,7 +1549,7 @@ impl Tab {
|
|||
self.render();
|
||||
}
|
||||
pub fn move_focus_right(&mut self) {
|
||||
if !self.has_panes() {
|
||||
if !self.has_selectable_panes() {
|
||||
return;
|
||||
}
|
||||
if self.fullscreen_is_active {
|
||||
|
|
@ -1540,7 +1557,7 @@ impl Tab {
|
|||
}
|
||||
let active_terminal = self.get_active_pane();
|
||||
if let Some(active) = active_terminal {
|
||||
let terminals = self.get_panes();
|
||||
let terminals = self.get_selectable_panes();
|
||||
let next_index = terminals
|
||||
.enumerate()
|
||||
.filter(|(_, (_, c))| {
|
||||
|
|
@ -1578,7 +1595,7 @@ impl Tab {
|
|||
})
|
||||
}
|
||||
fn panes_to_the_left_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
|
||||
if let Some(terminal) = &self.panes.get(&id) {
|
||||
if let Some(terminal) = self.panes.get(&id) {
|
||||
let upper_close_border = terminal.y();
|
||||
let lower_close_border = terminal.y() + terminal.rows() + 1;
|
||||
|
||||
|
|
@ -1601,7 +1618,7 @@ impl Tab {
|
|||
None
|
||||
}
|
||||
fn panes_to_the_right_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
|
||||
if let Some(terminal) = &self.panes.get(&id) {
|
||||
if let Some(terminal) = self.panes.get(&id) {
|
||||
let upper_close_border = terminal.y();
|
||||
let lower_close_border = terminal.y() + terminal.rows() + 1;
|
||||
|
||||
|
|
@ -1625,7 +1642,7 @@ impl Tab {
|
|||
None
|
||||
}
|
||||
fn panes_above_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
|
||||
if let Some(terminal) = &self.panes.get(&id) {
|
||||
if let Some(terminal) = self.panes.get(&id) {
|
||||
let left_close_border = terminal.x();
|
||||
let right_close_border = terminal.x() + terminal.columns() + 1;
|
||||
|
||||
|
|
@ -1647,8 +1664,8 @@ impl Tab {
|
|||
}
|
||||
None
|
||||
}
|
||||
fn terminals_below_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
|
||||
if let Some(terminal) = &self.panes.get(&id) {
|
||||
fn panes_below_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
|
||||
if let Some(terminal) = self.panes.get(&id) {
|
||||
let left_close_border = terminal.x();
|
||||
let right_close_border = terminal.x() + terminal.columns() + 1;
|
||||
|
||||
|
|
@ -1681,9 +1698,17 @@ impl Tab {
|
|||
}
|
||||
}
|
||||
}
|
||||
pub fn get_pane_ids(&mut self) -> Vec<PaneId> {
|
||||
pub fn get_pane_ids(&self) -> Vec<PaneId> {
|
||||
self.get_panes().map(|(&pid, _)| pid).collect()
|
||||
}
|
||||
pub fn set_pane_selectable(&mut self, id: PaneId, selectable: bool) {
|
||||
if let Some(pane) = self.panes.get_mut(&id) {
|
||||
pane.set_selectable(selectable);
|
||||
if self.get_active_pane_id() == Some(id) && !selectable {
|
||||
self.active_terminal = self.next_active_pane(self.get_pane_ids())
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn close_pane(&mut self, id: PaneId) {
|
||||
if self.panes.get(&id).is_some() {
|
||||
self.close_pane_without_rerender(id);
|
||||
|
|
@ -1699,7 +1724,7 @@ impl Tab {
|
|||
// 1 for the border
|
||||
}
|
||||
if self.active_terminal == Some(id) {
|
||||
self.active_terminal = Some(*terminals.last().unwrap());
|
||||
self.active_terminal = self.next_active_pane(terminals);
|
||||
}
|
||||
} else if let Some(terminals) = self.panes_to_the_right_between_aligning_borders(id) {
|
||||
for terminal_id in terminals.iter() {
|
||||
|
|
@ -1707,7 +1732,7 @@ impl Tab {
|
|||
// 1 for the border
|
||||
}
|
||||
if self.active_terminal == Some(id) {
|
||||
self.active_terminal = Some(*terminals.last().unwrap());
|
||||
self.active_terminal = self.next_active_pane(terminals);
|
||||
}
|
||||
} else if let Some(terminals) = self.panes_above_between_aligning_borders(id) {
|
||||
for terminal_id in terminals.iter() {
|
||||
|
|
@ -1715,21 +1740,21 @@ impl Tab {
|
|||
// 1 for the border
|
||||
}
|
||||
if self.active_terminal == Some(id) {
|
||||
self.active_terminal = Some(*terminals.last().unwrap());
|
||||
self.active_terminal = self.next_active_pane(terminals);
|
||||
}
|
||||
} else if let Some(terminals) = self.terminals_below_between_aligning_borders(id) {
|
||||
} else if let Some(terminals) = self.panes_below_between_aligning_borders(id) {
|
||||
for terminal_id in terminals.iter() {
|
||||
self.increase_pane_height_up(&terminal_id, terminal_to_close_height + 1);
|
||||
// 1 for the border
|
||||
}
|
||||
if self.active_terminal == Some(id) {
|
||||
self.active_terminal = Some(*terminals.last().unwrap());
|
||||
self.active_terminal = self.next_active_pane(terminals);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
self.panes.remove(&id);
|
||||
if !self.has_panes() {
|
||||
self.active_terminal = None;
|
||||
if self.active_terminal.is_none() {
|
||||
self.active_terminal = self.next_active_pane(self.get_pane_ids());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,4 +10,5 @@ parts:
|
|||
- direction: Horizontal
|
||||
- direction: Vertical
|
||||
split_size:
|
||||
Fixed: 1
|
||||
Fixed: 1
|
||||
plugin: status-bar.wasm
|
||||
|
|
@ -2,19 +2,22 @@ use std::{path::PathBuf, sync::mpsc::Sender};
|
|||
use wasmer::{imports, Function, ImportObject, Store, WasmerEnv};
|
||||
use wasmer_wasi::WasiEnv;
|
||||
|
||||
use crate::{panes::PaneId, pty_bus::PtyInstruction, SenderWithContext};
|
||||
use crate::{panes::PaneId, pty_bus::PtyInstruction, screen::ScreenInstruction, SenderWithContext};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PluginInstruction {
|
||||
Load(Sender<u32>, PathBuf),
|
||||
Draw(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols
|
||||
Input(PaneId, Vec<u8>), // pane id, input bytes
|
||||
Input(u32, Vec<u8>), // plugin id, input bytes
|
||||
GlobalInput(Vec<u8>), // input bytes
|
||||
Unload(u32),
|
||||
Quit,
|
||||
}
|
||||
|
||||
#[derive(WasmerEnv, Clone)]
|
||||
pub struct PluginEnv {
|
||||
pub plugin_id: u32,
|
||||
pub send_screen_instructions: SenderWithContext<ScreenInstruction>,
|
||||
pub send_pty_instructions: SenderWithContext<PtyInstruction>, // FIXME: This should be a big bundle of all of the channels
|
||||
pub wasi_env: WasiEnv,
|
||||
}
|
||||
|
|
@ -24,7 +27,8 @@ pub struct PluginEnv {
|
|||
pub fn mosaic_imports(store: &Store, plugin_env: &PluginEnv) -> ImportObject {
|
||||
imports! {
|
||||
"mosaic" => {
|
||||
"host_open_file" => Function::new_native_with_env(store, plugin_env.clone(), host_open_file)
|
||||
"host_open_file" => Function::new_native_with_env(store, plugin_env.clone(), host_open_file),
|
||||
"host_set_selectable" => Function::new_native_with_env(store, plugin_env.clone(), host_set_selectable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -38,6 +42,18 @@ fn host_open_file(plugin_env: &PluginEnv) {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
// FIXME: Think about these naming conventions – should everything be prefixed by 'host'?
|
||||
fn host_set_selectable(plugin_env: &PluginEnv, selectable: i32) {
|
||||
let selectable = selectable != 0;
|
||||
plugin_env
|
||||
.send_screen_instructions
|
||||
.send(ScreenInstruction::SetSelectable(
|
||||
PaneId::Plugin(plugin_env.plugin_id),
|
||||
selectable,
|
||||
))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
// Helper Functions ---------------------------------------------------------------------------------------------------
|
||||
|
||||
// FIXME: Unwrap city
|
||||
|
|
|
|||
BIN
status-bar.wasm
Executable file
BIN
status-bar.wasm
Executable file
Binary file not shown.
Loading…
Add table
Reference in a new issue