aboutsummaryrefslogtreecommitdiff
path: root/src/app/api/workspaces.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-06-14 02:43:45 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-06-14 03:47:07 +0300
commitfbd20ad6e488fb3b9efc1612fdffee6e672976c1 (patch)
treed21daf93241786f8aa6fde23b41cdb9e15182b79 /src/app/api/workspaces.rs
parentd35c642ef36ee5ac2afe7c1b18ad5a717bc807d8 (diff)
feat: add plugin v1 system
Add manifest-driven plugin actions, event hooks, pane entrypoints, link handlers, and host APIs. Support plugin link, GitHub install, build commands, installed plugin registry, pane movement, runtime context, and plugin docs.
Diffstat (limited to 'src/app/api/workspaces.rs')
-rw-r--r--src/app/api/workspaces.rs59
1 files changed, 57 insertions, 2 deletions
diff --git a/src/app/api/workspaces.rs b/src/app/api/workspaces.rs
index e1966adf..cdfd4ec5 100644
--- a/src/app/api/workspaces.rs
+++ b/src/app/api/workspaces.rs
@@ -51,7 +51,11 @@ impl App {
.and_then(|ws_idx| self.seed_cwd_from_workspace(ws_idx));
self.resolve_new_terminal_cwd(follow_cwd)
});
- match self.create_workspace_with_options(cwd, params.focus) {
+ let extra_env = match super::env::normalize_launch_env(params.env) {
+ Ok(env) => env,
+ Err((code, message)) => return encode_error(id, &code, message),
+ };
+ match self.create_workspace_with_launch_env(cwd, params.focus, extra_env) {
Ok(index) => {
if let Some(label) = params.label {
if let Some(workspace) = self.state.workspaces.get_mut(index) {
@@ -147,12 +151,30 @@ impl App {
return workspace_not_found(id, &target.workspace_id);
}
let workspace_id = self.public_workspace_id(index);
+ let workspace = self.workspace_info(index);
+ let pane_ids = self
+ .state
+ .workspaces
+ .get(index)
+ .map(|ws| {
+ ws.tabs
+ .iter()
+ .flat_map(|tab| tab.layout.pane_ids())
+ .collect::<Vec<_>>()
+ })
+ .unwrap_or_default();
self.state.selected = index;
self.state.close_selected_workspace();
+ for pane_id in pane_ids {
+ self.state.plugin_panes.remove(&pane_id);
+ }
self.shutdown_detached_terminal_runtimes();
self.emit_event(EventEnvelope {
event: EventKind::WorkspaceClosed,
- data: EventData::WorkspaceClosed { workspace_id },
+ data: EventData::WorkspaceClosed {
+ workspace_id,
+ workspace: Some(workspace),
+ },
});
encode_success(id, ResponseResult::Ok {})
@@ -208,4 +230,37 @@ mod tests {
assert_eq!(app.state.request_remove_linked_worktree, None);
assert!(app.state.workspaces.is_empty());
}
+
+ #[test]
+ fn api_workspace_close_event_includes_final_worktree_snapshot() {
+ let event_hub = crate::api::EventHub::default();
+ let (_api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel();
+ let mut app = App::new(&Config::default(), true, None, api_rx, event_hub.clone());
+ app.state.workspaces = app_with_linked_worktree().state.workspaces;
+ let workspace_id = app.state.workspaces[0].id.clone();
+
+ let response = app.handle_workspace_close(
+ "req".into(),
+ WorkspaceTarget {
+ workspace_id: workspace_id.clone(),
+ },
+ );
+
+ let success: SuccessResponse = serde_json::from_str(&response).unwrap();
+ assert_eq!(success.id, "req");
+ let events = event_hub.events_after(0);
+ assert!(events.iter().any(|(_, event)| {
+ matches!(
+ &event.data,
+ EventData::WorkspaceClosed {
+ workspace_id: closed_id,
+ workspace: Some(workspace),
+ } if closed_id == &workspace_id
+ && workspace
+ .worktree
+ .as_ref()
+ .is_some_and(|worktree| worktree.is_linked_worktree)
+ )
+ }));
+ }
}