aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrooks J Rady <b.j.rady@gmail.com>2021-01-11 07:33:35 +0000
committerBrooks J Rady <b.j.rady@gmail.com>2021-01-11 07:33:35 +0000
commitefcd36a52c203b082e931ae06cecfb475e61547f (patch)
treeb0062a93edb85cb15346c126509693d9c104bdf9
parentAdd a plugin callback for global keypresses (diff)
downloadsl0ppij-efcd36a52c203b082e931ae06cecfb475e61547f.tar.gz
sl0ppij-efcd36a52c203b082e931ae06cecfb475e61547f.tar.xz
sl0ppij-efcd36a52c203b082e931ae06cecfb475e61547f.zip
Added the set_selectable plugin API function
-rw-r--r--src/errors.rs4
-rw-r--r--src/input.rs21
-rw-r--r--src/main.rs47
-rw-r--r--src/panes/plugin_pane.rs8
-rw-r--r--src/panes/terminal_pane.rs8
-rw-r--r--src/pty_bus.rs12
-rw-r--r--src/screen.rs3
-rw-r--r--src/tab.rs105
-rw-r--r--src/tests/fixtures/layouts/panes-with-plugins.yaml3
-rw-r--r--src/wasm_vm.rs22
-rwxr-xr-xstatus-bar.wasmbin0 -> 482412 bytes
11 files changed, 170 insertions, 63 deletions
diff --git a/src/errors.rs b/src/errors.rs
index e53bbc30..bbe85ec8 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -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,
}
diff --git a/src/input.rs b/src/input.rs
index cc144361..c947b7fb 100644
--- a/src/input.rs
+++ b/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();
diff --git a/src/main.rs b/src/main.rs
index 6800691d..c449f89a 100644
--- a/src/main.rs
+++ b/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";
diff --git a/src/panes/plugin_pane.rs b/src/panes/plugin_pane.rs
index 1573d577..a93ff8c0 100644
--- a/src/panes/plugin_pane.rs
+++ b/src/panes/plugin_pane.rs
@@ -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 {
diff --git a/src/panes/terminal_pane.rs b/src/panes/terminal_pane.rs
index 0d04c681..d15c7649 100644
--- a/src/panes/terminal_pane.rs
+++ b/src/panes/terminal_pane.rs
@@ -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. "")
@@ -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,
diff --git a/src/pty_bus.rs b/src/pty_bus.rs
index e635b176..ba5a608b 100644
--- a/src/pty_bus.rs
+++ b/src/pty_bus.rs
@@ -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);
+ });
}
}
diff --git a/src/screen.rs b/src/screen.rs
index 365d1d7a..5e4d1ae9 100644
--- a/src/screen.rs
+++ b/src/screen.rs
@@ -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))
diff --git a/src/tab.rs b/src/tab.rs
index 9990026a..6c65958f 100644
--- a/src/tab.rs
+++ b/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());
}
}
}
diff --git a/src/tests/fixtures/layouts/panes-with-plugins.yaml b/src/tests/fixtures/layouts/panes-with-plugins.yaml
index 9bb35e08..40dde92b 100644
--- a/src/tests/fixtures/layouts/panes-with-plugins.yaml
+++ b/src/tests/fixtures/layouts/panes-with-plugins.yaml
@@ -10,4 +10,5 @@ parts:
- direction: Horizontal
- direction: Vertical
split_size:
- Fixed: 1 \ No newline at end of file
+ Fixed: 1
+ plugin: status-bar.wasm \ No newline at end of file
diff --git a/src/wasm_vm.rs b/src/wasm_vm.rs
index 5324ee19..acb9e013 100644
--- a/src/wasm_vm.rs
+++ b/src/wasm_vm.rs
@@ -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
diff --git a/status-bar.wasm b/status-bar.wasm
new file mode 100755
index 00000000..39e081ff
--- /dev/null
+++ b/status-bar.wasm
Binary files differ