diff options
Diffstat (limited to 'src/api')
| -rw-r--r-- | src/api/mod.rs | 3 | ||||
| -rw-r--r-- | src/api/schema.rs | 202 | ||||
| -rw-r--r-- | src/api/server.rs | 4 | ||||
| -rw-r--r-- | src/api/subscriptions.rs | 8 |
4 files changed, 217 insertions, 0 deletions
diff --git a/src/api/mod.rs b/src/api/mod.rs index 34b37138..e3ad58c4 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -26,6 +26,9 @@ pub(crate) fn request_changes_ui(request: &Request) -> bool { | Method::WorkspaceFocus(_) | Method::WorkspaceRename(_) | Method::WorkspaceClose(_) + | Method::WorktreeCreate(_) + | Method::WorktreeOpen(_) + | Method::WorktreeRemove(_) | Method::TabCreate(_) | Method::TabFocus(_) | Method::TabRename(_) diff --git a/src/api/schema.rs b/src/api/schema.rs index 7224d419..17a5d35e 100644 --- a/src/api/schema.rs +++ b/src/api/schema.rs @@ -28,6 +28,14 @@ pub enum Method { WorkspaceRename(WorkspaceRenameParams), #[serde(rename = "workspace.close")] WorkspaceClose(WorkspaceTarget), + #[serde(rename = "worktree.list")] + WorktreeList(WorktreeListParams), + #[serde(rename = "worktree.create")] + WorktreeCreate(WorktreeCreateParams), + #[serde(rename = "worktree.open")] + WorktreeOpen(WorktreeOpenParams), + #[serde(rename = "worktree.remove")] + WorktreeRemove(WorktreeRemoveParams), #[serde(rename = "tab.create")] TabCreate(TabCreateParams), #[serde(rename = "tab.list")] @@ -127,6 +135,55 @@ pub struct WorkspaceRenameParams { pub label: String, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct WorktreeListParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub workspace_id: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cwd: Option<String>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct WorktreeCreateParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub workspace_id: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cwd: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub branch: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub base: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub path: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub label: Option<String>, + #[serde(default)] + pub focus: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct WorktreeOpenParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub workspace_id: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cwd: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub path: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub branch: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub label: Option<String>, + #[serde(default)] + pub focus: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct WorktreeRemoveParams { + pub workspace_id: String, + #[serde(default)] + pub force: bool, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct TabCreateParams { #[serde(default, skip_serializing_if = "Option::is_none")] @@ -320,6 +377,10 @@ pub struct EventsSubscribeParams { pub enum Subscription { #[serde(rename = "workspace.created")] WorkspaceCreated {}, + #[serde(rename = "workspace.updated")] + WorkspaceUpdated {}, + #[serde(rename = "workspace.renamed")] + WorkspaceRenamed {}, #[serde(rename = "workspace.closed")] WorkspaceClosed {}, #[serde(rename = "workspace.focused")] @@ -415,6 +476,9 @@ pub enum EventMatch { #[serde(default, skip_serializing_if = "Option::is_none")] workspace_id: Option<String>, }, + WorkspaceUpdated { + workspace_id: String, + }, WorkspaceClosed { workspace_id: String, }, @@ -478,6 +542,7 @@ pub enum EventMatch { #[serde(rename_all = "snake_case")] pub enum EventKind { WorkspaceCreated, + WorkspaceUpdated, WorkspaceClosed, WorkspaceRenamed, WorkspaceFocused, @@ -530,6 +595,28 @@ pub enum ResponseResult { WorkspaceList { workspaces: Vec<WorkspaceInfo>, }, + WorktreeList { + source: WorktreeSourceInfo, + worktrees: Vec<WorktreeInfo>, + }, + WorktreeCreated { + workspace: WorkspaceInfo, + tab: TabInfo, + root_pane: PaneInfo, + worktree: WorktreeInfo, + }, + WorktreeOpened { + workspace: WorkspaceInfo, + tab: TabInfo, + root_pane: PaneInfo, + worktree: WorktreeInfo, + already_open: bool, + }, + WorktreeRemoved { + workspace_id: String, + path: String, + forced: bool, + }, TabInfo { tab: TabInfo, }, @@ -594,6 +681,41 @@ pub struct WorkspaceInfo { pub tab_count: usize, pub active_tab_id: String, pub agent_status: AgentStatus, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub worktree: Option<WorkspaceWorktreeInfo>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct WorkspaceWorktreeInfo { + pub repo_key: String, + pub repo_name: String, + pub repo_root: String, + pub checkout_path: String, + pub is_linked_worktree: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct WorktreeSourceInfo { + pub repo_key: String, + pub repo_name: String, + pub repo_root: String, + pub source_checkout_path: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub source_workspace_id: Option<String>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct WorktreeInfo { + pub path: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub branch: Option<String>, + pub is_bare: bool, + pub is_detached: bool, + pub is_prunable: bool, + pub is_linked_worktree: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub open_workspace_id: Option<String>, + pub label: String, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -716,6 +838,9 @@ pub enum EventData { WorkspaceCreated { workspace: WorkspaceInfo, }, + WorkspaceUpdated { + workspace: WorkspaceInfo, + }, WorkspaceClosed { workspace_id: String, }, @@ -1103,6 +1228,83 @@ mod tests { } #[test] + fn worktree_request_and_response_round_trip() { + let request = Request { + id: "req_worktree".into(), + method: Method::WorktreeCreate(WorktreeCreateParams { + workspace_id: Some("1".into()), + branch: Some("worktree/api".into()), + base: Some("HEAD".into()), + focus: true, + ..WorktreeCreateParams::default() + }), + }; + let json = serde_json::to_string(&request).unwrap(); + let restored: Request = serde_json::from_str(&json).unwrap(); + assert_eq!(restored, request); + + let response = SuccessResponse { + id: "req_worktree".into(), + result: ResponseResult::WorktreeCreated { + workspace: WorkspaceInfo { + workspace_id: "w_1".into(), + number: 2, + label: "herdr".into(), + focused: true, + pane_count: 1, + tab_count: 1, + active_tab_id: "w_1:1".into(), + agent_status: AgentStatus::Unknown, + worktree: Some(WorkspaceWorktreeInfo { + repo_key: "/repo/herdr/.git".into(), + repo_name: "herdr".into(), + repo_root: "/repo/herdr".into(), + checkout_path: "/worktrees/herdr/worktree-api".into(), + is_linked_worktree: true, + }), + }, + tab: TabInfo { + tab_id: "w_1:1".into(), + workspace_id: "w_1".into(), + number: 1, + label: "herdr".into(), + focused: true, + pane_count: 1, + agent_status: AgentStatus::Unknown, + }, + root_pane: PaneInfo { + pane_id: "w_1-1".into(), + terminal_id: "term_1".into(), + workspace_id: "w_1".into(), + tab_id: "w_1:1".into(), + focused: true, + cwd: Some("/worktrees/herdr/worktree-api".into()), + label: None, + agent: None, + agent_status: AgentStatus::Unknown, + custom_status: None, + revision: 0, + }, + worktree: WorktreeInfo { + path: "/worktrees/herdr/worktree-api".into(), + branch: Some("worktree/api".into()), + is_bare: false, + is_detached: false, + is_prunable: false, + is_linked_worktree: true, + open_workspace_id: Some("w_1".into()), + label: "herdr".into(), + }, + }, + }; + let json = serde_json::to_string(&response).unwrap(); + assert!(json.contains("\"type\":\"worktree_created\"")); + assert!(json.contains("\"worktree\"")); + let restored: SuccessResponse = serde_json::from_str(&json).unwrap(); + assert_eq!(restored, response); + } + + #[test] fn create_response_round_trips_with_root_pane() { let response = SuccessResponse { id: "req_2".into(), diff --git a/src/api/server.rs b/src/api/server.rs index 2f9a423e..513262bc 100644 --- a/src/api/server.rs +++ b/src/api/server.rs @@ -245,6 +245,10 @@ fn api_method_name(method: &Method) -> &'static str { Method::WorkspaceFocus(_) => "workspace.focus", Method::WorkspaceRename(_) => "workspace.rename", Method::WorkspaceClose(_) => "workspace.close", + Method::WorktreeList(_) => "worktree.list", + Method::WorktreeCreate(_) => "worktree.create", + Method::WorktreeOpen(_) => "worktree.open", + Method::WorktreeRemove(_) => "worktree.remove", Method::TabCreate(_) => "tab.create", Method::TabList(_) => "tab.list", Method::TabGet(_) => "tab.get", diff --git a/src/api/subscriptions.rs b/src/api/subscriptions.rs index 891b743a..c5c43e20 100644 --- a/src/api/subscriptions.rs +++ b/src/api/subscriptions.rs @@ -76,6 +76,14 @@ impl ActiveSubscription { event_kind: crate::api::schema::EventKind::WorkspaceCreated, last_sequence: 0, })), + Subscription::WorkspaceUpdated {} => Ok(Self::Event(ActiveEventSubscription { + event_kind: crate::api::schema::EventKind::WorkspaceUpdated, + last_sequence: 0, + })), + Subscription::WorkspaceRenamed {} => Ok(Self::Event(ActiveEventSubscription { + event_kind: crate::api::schema::EventKind::WorkspaceRenamed, + last_sequence: 0, + })), Subscription::WorkspaceClosed {} => Ok(Self::Event(ActiveEventSubscription { event_kind: crate::api::schema::EventKind::WorkspaceClosed, last_sequence: 0, |
