Skip to content

Commit

Permalink
feat(plugins): async plugin loading (#2327)
Browse files Browse the repository at this point in the history
* work

* refactor(plugins): break down start plugin async function

* work

* loading messages

* nice ui

* floating panes and error handling

* cleanups and conflicting plugin/direction

* find exact pane when relayouting

* fix plugin pane titles

* kill loading tasks on exit

* refactor: move stuff around

* style(fmt): rustfmt

* various fixes and refactors
  • Loading branch information
imsnif authored Mar 27, 2023
1 parent 7b609b0 commit 341f9eb
Show file tree
Hide file tree
Showing 26 changed files with 1,455 additions and 310 deletions.
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ fn main() {
{
let command_cli_action = CliAction::NewPane {
command,
plugin: None,
direction,
cwd,
floating,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
assertion_line: 1671
assertion_line: 1640
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1
Expand All @@ -25,5 +25,5 @@ expression: last_snapshot
│ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
assertion_line: 803
assertion_line: 804
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1
Expand All @@ -25,5 +25,5 @@ expression: last_snapshot
│ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Ctrl + <g> LOCK  <> PANE  <> TAB  <> RESIZE  <> MOVE  <> SEARCH  <> SESSION  <> QUIT 
Ctrl + <g> LOCK  <> PANE  <> TAB  <> RESIZE  <> MOVE  <> SEARCH  <> SESSION  <> QUIT   BASE 
-- INTERFACE LOCKED --
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
assertion_line: 107
assertion_line: 108
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1
Expand All @@ -25,5 +25,5 @@ expression: last_snapshot
│ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
assertion_line: 398
assertion_line: 987
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1
Expand All @@ -25,5 +25,5 @@ expression: last_snapshot
│ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
<F1> LOCK  <F2> PANE  <F3> TAB  <F4> RESIZE  <F5> MOVE  <F6> SEARCH  <F7> SESSION  <F8> QUIT 
<F1> LOCK  <F2> PANE  <F3> TAB  <F4> RESIZE  <F5> MOVE  <F6> SEARCH  <F7> SESSION  <F8> QUIT   BASE 
Tip: UNBOUND => open new pane. UNBOUND => navigate between panes. UNBOUND => increase/decrease pane size.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
assertion_line: 1949
assertion_line: 1881
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1
Expand All @@ -25,5 +25,5 @@ expression: last_snapshot
│ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
assertion_line: 1900
assertion_line: 1832
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1
Expand All @@ -25,5 +25,5 @@ expression: last_snapshot
│ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
42 changes: 42 additions & 0 deletions zellij-server/src/background_jobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ use zellij_utils::async_std::task;
use zellij_utils::errors::{prelude::*, BackgroundJobContext, ContextType};

use std::collections::HashMap;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use std::time::{Duration, Instant};

use crate::panes::PaneId;
Expand All @@ -11,23 +15,31 @@ use crate::thread_bus::Bus;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum BackgroundJob {
DisplayPaneError(Vec<PaneId>, String),
AnimatePluginLoading(u32), // u32 - plugin_id
StopPluginLoadingAnimation(u32), // u32 - plugin_id
Exit,
}

impl From<&BackgroundJob> for BackgroundJobContext {
fn from(background_job: &BackgroundJob) -> Self {
match *background_job {
BackgroundJob::DisplayPaneError(..) => BackgroundJobContext::DisplayPaneError,
BackgroundJob::AnimatePluginLoading(..) => BackgroundJobContext::AnimatePluginLoading,
BackgroundJob::StopPluginLoadingAnimation(..) => {
BackgroundJobContext::StopPluginLoadingAnimation
},
BackgroundJob::Exit => BackgroundJobContext::Exit,
}
}
}

static FLASH_DURATION_MS: u64 = 1000;
static PLUGIN_ANIMATION_OFFSET_DURATION_MD: u64 = 500;

pub(crate) fn background_jobs_main(bus: Bus<BackgroundJob>) -> Result<()> {
let err_context = || "failed to write to pty".to_string();
let mut running_jobs: HashMap<BackgroundJob, Instant> = HashMap::new();
let mut loading_plugins: HashMap<u32, Arc<AtomicBool>> = HashMap::new(); // u32 - plugin_id

loop {
let (event, mut err_ctx) = bus.recv().with_context(err_context)?;
Expand All @@ -54,7 +66,37 @@ pub(crate) fn background_jobs_main(bus: Bus<BackgroundJob>) -> Result<()> {
}
});
},
BackgroundJob::AnimatePluginLoading(pid) => {
let loading_plugin = Arc::new(AtomicBool::new(true));
if job_already_running(job, &mut running_jobs) {
continue;
}
task::spawn({
let senders = bus.senders.clone();
let loading_plugin = loading_plugin.clone();
async move {
while loading_plugin.load(Ordering::SeqCst) {
let _ = senders.send_to_screen(
ScreenInstruction::ProgressPluginLoadingOffset(pid),
);
task::sleep(std::time::Duration::from_millis(
PLUGIN_ANIMATION_OFFSET_DURATION_MD,
))
.await;
}
}
});
loading_plugins.insert(pid, loading_plugin);
},
BackgroundJob::StopPluginLoadingAnimation(pid) => {
if let Some(loading_plugin) = loading_plugins.remove(&pid) {
loading_plugin.store(false, Ordering::SeqCst);
}
},
BackgroundJob::Exit => {
for loading_plugin in loading_plugins.values() {
loading_plugin.store(false, Ordering::SeqCst);
}
return Ok(());
},
}
Expand Down
40 changes: 38 additions & 2 deletions zellij-server/src/panes/plugin_pane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use crate::panes::{grid::Grid, sixel::SixelImageStore, LinkHandler, PaneId};
use crate::plugins::PluginInstruction;
use crate::pty::VteBytes;
use crate::tab::Pane;
use crate::ui::pane_boundaries_frame::{FrameParams, PaneFrame};
use crate::ui::{
loading_indication::LoadingIndication,
pane_boundaries_frame::{FrameParams, PaneFrame},
};
use crate::ClientId;
use std::cell::RefCell;
use std::rc::Rc;
Expand Down Expand Up @@ -67,6 +70,7 @@ pub(crate) struct PluginPane {
borderless: bool,
pane_frame_color_override: Option<(PaletteColor, Option<String>)>,
invoked_with: Option<Run>,
loading_indication: LoadingIndication,
}

impl PluginPane {
Expand All @@ -81,10 +85,13 @@ impl PluginPane {
terminal_emulator_color_codes: Rc<RefCell<HashMap<usize, String>>>,
link_handler: Rc<RefCell<LinkHandler>>,
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
currently_connected_clients: Vec<ClientId>,
style: Style,
invoked_with: Option<Run>,
) -> Self {
Self {
let loading_indication = LoadingIndication::new(title.clone()).with_colors(style.colors);
let initial_loading_message = loading_indication.to_string();
let mut plugin = PluginPane {
pid,
should_render: HashMap::new(),
selectable: true,
Expand All @@ -108,7 +115,12 @@ impl PluginPane {
style,
pane_frame_color_override: None,
invoked_with,
loading_indication,
};
for client_id in currently_connected_clients {
plugin.handle_plugin_bytes(client_id, initial_loading_message.as_bytes().to_vec());
}
plugin
}
}

Expand Down Expand Up @@ -513,6 +525,24 @@ impl Pane for PluginPane {
fn set_title(&mut self, title: String) {
self.pane_title = title;
}
fn update_loading_indication(&mut self, loading_indication: LoadingIndication) {
if self.loading_indication.ended {
return;
}
self.loading_indication.merge(loading_indication);
self.handle_plugin_bytes_for_all_clients(
self.loading_indication.to_string().as_bytes().to_vec(),
);
}
fn progress_animation_offset(&mut self) {
if self.loading_indication.ended {
return;
}
self.loading_indication.progress_animation_offset();
self.handle_plugin_bytes_for_all_clients(
self.loading_indication.to_string().as_bytes().to_vec(),
);
}
}

impl PluginPane {
Expand All @@ -527,4 +557,10 @@ impl PluginPane {
fn set_client_should_render(&mut self, client_id: ClientId, should_render: bool) {
self.should_render.insert(client_id, should_render);
}
fn handle_plugin_bytes_for_all_clients(&mut self, bytes: VteBytes) {
let client_ids: Vec<ClientId> = self.grids.keys().copied().collect();
for client_id in client_ids {
self.handle_plugin_bytes(client_id, bytes.clone());
}
}
}
38 changes: 34 additions & 4 deletions zellij-server/src/plugins/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod start_plugin;
mod wasm_bridge;
use log::info;
use std::{collections::HashMap, fs, path::PathBuf};
use wasmer::Store;

use crate::screen::ScreenInstruction;
use crate::{pty::PtyInstruction, thread_bus::Bus, ClientId};

use wasm_bridge::WasmBridge;
Expand All @@ -20,7 +22,14 @@ use zellij_utils::{

#[derive(Clone, Debug)]
pub enum PluginInstruction {
Load(RunPlugin, usize, ClientId, Size), // plugin metadata, tab_index, client_ids
Load(
Option<bool>, // should float
Option<String>, // pane title
RunPlugin,
usize, // tab index
ClientId,
Size,
),
Update(Vec<(Option<u32>, Option<ClientId>, Event)>), // Focused plugin / broadcast, client_id, event data
Unload(u32), // plugin_id
Resize(u32, usize, usize), // plugin_id, columns, rows
Expand All @@ -33,6 +42,7 @@ pub enum PluginInstruction {
usize, // tab_index
ClientId,
),
ApplyCachedEvents(u32), // u32 is the plugin id
Exit,
}

Expand All @@ -47,6 +57,7 @@ impl From<&PluginInstruction> for PluginContext {
PluginInstruction::AddClient(_) => PluginContext::AddClient,
PluginInstruction::RemoveClient(_) => PluginContext::RemoveClient,
PluginInstruction::NewTab(..) => PluginContext::NewTab,
PluginInstruction::ApplyCachedEvents(..) => PluginContext::ApplyCachedEvents,
}
}
}
Expand All @@ -69,8 +80,21 @@ pub(crate) fn plugin_thread_main(
let (event, mut err_ctx) = bus.recv().expect("failed to receive event on channel");
err_ctx.add_call(ContextType::Plugin((&event).into()));
match event {
PluginInstruction::Load(run, tab_index, client_id, size) => {
wasm_bridge.load_plugin(&run, tab_index, size, client_id)?;
PluginInstruction::Load(should_float, pane_title, run, tab_index, client_id, size) => {
match wasm_bridge.load_plugin(&run, tab_index, size, client_id) {
Ok(plugin_id) => {
drop(bus.senders.send_to_screen(ScreenInstruction::AddPlugin(
should_float,
run,
pane_title,
tab_index,
plugin_id,
)));
},
Err(e) => {
log::error!("Failed to load plugin: {e}");
},
}
},
PluginInstruction::Update(updates) => {
wasm_bridge.update_plugins(updates)?;
Expand Down Expand Up @@ -126,7 +150,13 @@ pub(crate) fn plugin_thread_main(
client_id,
)));
},
PluginInstruction::Exit => break,
PluginInstruction::ApplyCachedEvents(plugin_id) => {
wasm_bridge.apply_cached_events(plugin_id)?;
},
PluginInstruction::Exit => {
wasm_bridge.cleanup();
break;
},
}
}
info!("wasm main thread exits");
Expand Down
Loading

0 comments on commit 341f9eb

Please sign in to comment.