Skip to main content

rmux_client/commands/
window.rs

1use rmux_proto::{
2    KillWindowRequest, LastWindowRequest, LayoutName, LinkWindowRequest, ListWindowsRequest,
3    MoveWindowRequest, MoveWindowTarget, NewWindowRequest, NextWindowRequest,
4    PreviousWindowRequest, RenameWindowRequest, Request, Response, RotateWindowDirection,
5    RotateWindowRequest, SelectCustomLayoutRequest, SelectLayoutRequest, SelectLayoutTarget,
6    SelectWindowRequest, SessionName, SplitDirection, SplitWindowExtRequest, SplitWindowRequest,
7    SplitWindowTarget, SwapWindowRequest, UnlinkWindowRequest, WindowTarget,
8};
9
10use crate::{connection::Connection, ClientError};
11
12/// Full options for a `split-window` request.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct SplitWindowOptions {
15    /// The exact split target.
16    pub target: SplitWindowTarget,
17    /// Axis on which to split (`Vertical` = side-by-side, `Horizontal` = stacked).
18    pub direction: SplitDirection,
19    /// `true` to insert the new pane *before* the target on the chosen axis
20    /// (tmux `-b`); `false` to insert after (default).
21    pub before: bool,
22    /// Optional per-spawn environment overrides in `NAME=VALUE` form.
23    pub environment: Option<Vec<String>>,
24    /// Optional command argv for the new pane.
25    pub command: Option<Vec<String>>,
26}
27
28impl Connection {
29    /// Sends a `new-window` request over the detached RPC channel.
30    pub fn new_window(
31        &mut self,
32        target: rmux_proto::SessionName,
33        name: Option<String>,
34        detached: bool,
35    ) -> Result<Response, ClientError> {
36        self.new_window_with_environment(target, name, detached, None, None, None)
37    }
38
39    /// Sends a `new-window` request with explicit spawn environment overrides.
40    pub fn new_window_with_environment(
41        &mut self,
42        target: rmux_proto::SessionName,
43        name: Option<String>,
44        detached: bool,
45        environment: Option<Vec<String>>,
46        start_directory: Option<std::path::PathBuf>,
47        command: Option<Vec<String>>,
48    ) -> Result<Response, ClientError> {
49        self.new_window_at_with_environment(
50            target,
51            None,
52            name,
53            detached,
54            environment,
55            start_directory,
56            command,
57            false,
58        )
59    }
60
61    /// Sends a `new-window` request with an optional destination index.
62    #[allow(clippy::too_many_arguments)]
63    pub fn new_window_at_with_environment(
64        &mut self,
65        target: rmux_proto::SessionName,
66        target_window_index: Option<u32>,
67        name: Option<String>,
68        detached: bool,
69        environment: Option<Vec<String>>,
70        start_directory: Option<std::path::PathBuf>,
71        command: Option<Vec<String>>,
72        insert_at_target: bool,
73    ) -> Result<Response, ClientError> {
74        self.roundtrip(&Request::NewWindow(NewWindowRequest {
75            target,
76            name,
77            detached,
78            start_directory,
79            environment,
80            command,
81            target_window_index,
82            insert_at_target,
83        }))
84    }
85
86    /// Sends a `kill-window` request over the detached RPC channel.
87    pub fn kill_window(
88        &mut self,
89        target: WindowTarget,
90        kill_others: bool,
91    ) -> Result<Response, ClientError> {
92        self.roundtrip(&Request::KillWindow(KillWindowRequest {
93            target,
94            kill_all_others: kill_others,
95        }))
96    }
97
98    /// Sends a `select-window` request over the detached RPC channel.
99    pub fn select_window(&mut self, target: WindowTarget) -> Result<Response, ClientError> {
100        self.roundtrip(&Request::SelectWindow(SelectWindowRequest { target }))
101    }
102
103    /// Sends a `rename-window` request over the detached RPC channel.
104    pub fn rename_window(
105        &mut self,
106        target: WindowTarget,
107        new_name: String,
108    ) -> Result<Response, ClientError> {
109        self.roundtrip(&Request::RenameWindow(RenameWindowRequest {
110            target,
111            name: new_name,
112        }))
113    }
114
115    /// Sends a `next-window` request over the detached RPC channel.
116    pub fn next_window(
117        &mut self,
118        target: SessionName,
119        alerts_only: bool,
120    ) -> Result<Response, ClientError> {
121        self.roundtrip(&Request::NextWindow(NextWindowRequest {
122            target,
123            alerts_only,
124        }))
125    }
126
127    /// Sends a `previous-window` request over the detached RPC channel.
128    pub fn previous_window(
129        &mut self,
130        target: SessionName,
131        alerts_only: bool,
132    ) -> Result<Response, ClientError> {
133        self.roundtrip(&Request::PreviousWindow(PreviousWindowRequest {
134            target,
135            alerts_only,
136        }))
137    }
138
139    /// Sends a `last-window` request over the detached RPC channel.
140    pub fn last_window(&mut self, target: SessionName) -> Result<Response, ClientError> {
141        self.roundtrip(&Request::LastWindow(LastWindowRequest { target }))
142    }
143
144    /// Sends a `list-windows` request over the detached RPC channel.
145    pub fn list_windows(
146        &mut self,
147        target: SessionName,
148        format: Option<String>,
149    ) -> Result<Response, ClientError> {
150        self.roundtrip(&Request::ListWindows(ListWindowsRequest { target, format }))
151    }
152
153    /// Sends a `link-window` request over the detached RPC channel.
154    pub fn link_window(
155        &mut self,
156        source: WindowTarget,
157        target: WindowTarget,
158        after: bool,
159        before: bool,
160        kill_destination: bool,
161        detached: bool,
162    ) -> Result<Response, ClientError> {
163        self.roundtrip(&Request::LinkWindow(LinkWindowRequest {
164            source,
165            target,
166            after,
167            before,
168            kill_destination,
169            detached,
170        }))
171    }
172
173    /// Sends a `move-window` request over the detached RPC channel.
174    pub fn move_window(
175        &mut self,
176        source: Option<WindowTarget>,
177        target: MoveWindowTarget,
178        renumber: bool,
179        kill_destination: bool,
180        detached: bool,
181    ) -> Result<Response, ClientError> {
182        self.roundtrip(&Request::MoveWindow(MoveWindowRequest {
183            source,
184            target,
185            renumber,
186            kill_destination,
187            detached,
188        }))
189    }
190
191    /// Sends a `swap-window` request over the detached RPC channel.
192    pub fn swap_window(
193        &mut self,
194        source: WindowTarget,
195        target: WindowTarget,
196        detached: bool,
197    ) -> Result<Response, ClientError> {
198        self.roundtrip(&Request::SwapWindow(SwapWindowRequest {
199            source,
200            target,
201            detached,
202        }))
203    }
204
205    /// Sends a `rotate-window` request over the detached RPC channel.
206    pub fn rotate_window(
207        &mut self,
208        target: WindowTarget,
209        direction: RotateWindowDirection,
210    ) -> Result<Response, ClientError> {
211        self.rotate_window_with_zoom(target, direction, false)
212    }
213
214    /// Sends a `rotate-window` request with zoom save/restore over the detached RPC channel.
215    pub fn rotate_window_with_zoom(
216        &mut self,
217        target: WindowTarget,
218        direction: RotateWindowDirection,
219        restore_zoom: bool,
220    ) -> Result<Response, ClientError> {
221        self.roundtrip(&Request::RotateWindow(RotateWindowRequest {
222            target,
223            direction,
224            restore_zoom,
225        }))
226    }
227
228    /// Sends a `resize-window` request over the detached RPC channel.
229    pub fn resize_window(
230        &mut self,
231        target: WindowTarget,
232        width: Option<u16>,
233        height: Option<u16>,
234        adjustment: Option<rmux_proto::ResizeWindowAdjustment>,
235    ) -> Result<Response, ClientError> {
236        self.roundtrip(&Request::ResizeWindow(rmux_proto::ResizeWindowRequest {
237            target,
238            width,
239            height,
240            adjustment,
241        }))
242    }
243
244    /// Sends an `unlink-window` request over the detached RPC channel.
245    pub fn unlink_window(
246        &mut self,
247        target: WindowTarget,
248        kill_if_last: bool,
249    ) -> Result<Response, ClientError> {
250        self.roundtrip(&Request::UnlinkWindow(UnlinkWindowRequest {
251            target,
252            kill_if_last,
253        }))
254    }
255
256    /// Sends a `respawn-window` request over the detached RPC channel.
257    pub fn respawn_window(
258        &mut self,
259        target: WindowTarget,
260        kill: bool,
261    ) -> Result<Response, ClientError> {
262        self.respawn_window_with_environment(target, kill, None, None, None)
263    }
264
265    /// Sends a `respawn-window` request with explicit spawn environment overrides.
266    pub fn respawn_window_with_environment(
267        &mut self,
268        target: WindowTarget,
269        kill: bool,
270        environment: Option<Vec<String>>,
271        start_directory: Option<std::path::PathBuf>,
272        command: Option<Vec<String>>,
273    ) -> Result<Response, ClientError> {
274        self.roundtrip(&Request::RespawnWindow(rmux_proto::RespawnWindowRequest {
275            target,
276            kill,
277            start_directory,
278            environment,
279            command,
280        }))
281    }
282
283    /// Sends a `split-window` request over the detached RPC channel.
284    pub fn split_window(&mut self, target: SplitWindowTarget) -> Result<Response, ClientError> {
285        self.split_window_with_direction(target, SplitDirection::Vertical)
286    }
287
288    /// Sends a `split-window` request with an explicit direction over the detached RPC channel.
289    pub fn split_window_with_direction(
290        &mut self,
291        target: SplitWindowTarget,
292        direction: SplitDirection,
293    ) -> Result<Response, ClientError> {
294        self.split_window_with_direction_and_environment(target, direction, None)
295    }
296
297    /// Sends a `split-window` request with explicit spawn environment overrides.
298    pub fn split_window_with_direction_and_environment(
299        &mut self,
300        target: SplitWindowTarget,
301        direction: SplitDirection,
302        environment: Option<Vec<String>>,
303    ) -> Result<Response, ClientError> {
304        self.split_window_with_spawn(target, direction, environment, None)
305    }
306
307    /// Sends a `split-window` request with explicit spawn options.
308    ///
309    /// New pane is inserted *after* the target. To insert before (tmux `-b`),
310    /// use [`Connection::split_window_with_options`].
311    pub fn split_window_with_spawn(
312        &mut self,
313        target: SplitWindowTarget,
314        direction: SplitDirection,
315        environment: Option<Vec<String>>,
316        command: Option<Vec<String>>,
317    ) -> Result<Response, ClientError> {
318        self.split_window_with_options(SplitWindowOptions {
319            target,
320            direction,
321            before: false,
322            environment,
323            command,
324        })
325    }
326
327    /// Sends a `split-window` request with full options including `before`.
328    pub fn split_window_with_options(
329        &mut self,
330        options: SplitWindowOptions,
331    ) -> Result<Response, ClientError> {
332        let SplitWindowOptions {
333            target,
334            direction,
335            before,
336            environment,
337            command,
338        } = options;
339        if command.is_some() {
340            return self.roundtrip(&Request::SplitWindowExt(SplitWindowExtRequest {
341                target,
342                direction,
343                before,
344                environment,
345                command,
346            }));
347        }
348        self.roundtrip(&Request::SplitWindow(SplitWindowRequest {
349            target,
350            direction,
351            before,
352            environment,
353        }))
354    }
355
356    /// Sends a `select-layout` request over the detached RPC channel.
357    pub fn select_layout(
358        &mut self,
359        target: SelectLayoutTarget,
360        layout: LayoutName,
361    ) -> Result<Response, ClientError> {
362        self.roundtrip(&Request::SelectLayout(SelectLayoutRequest {
363            target,
364            layout,
365        }))
366    }
367
368    /// Sends a `select-layout` custom layout request over the detached RPC channel.
369    pub fn select_custom_layout(
370        &mut self,
371        target: SelectLayoutTarget,
372        layout: String,
373    ) -> Result<Response, ClientError> {
374        self.roundtrip(&Request::SelectCustomLayout(SelectCustomLayoutRequest {
375            target,
376            layout,
377        }))
378    }
379
380    /// Sends a `next-layout` request over the detached RPC channel.
381    pub fn next_layout(&mut self, target: WindowTarget) -> Result<Response, ClientError> {
382        self.roundtrip(&Request::NextLayout(rmux_proto::NextLayoutRequest {
383            target,
384        }))
385    }
386
387    /// Sends a `previous-layout` request over the detached RPC channel.
388    pub fn previous_layout(&mut self, target: WindowTarget) -> Result<Response, ClientError> {
389        self.roundtrip(&Request::PreviousLayout(
390            rmux_proto::PreviousLayoutRequest { target },
391        ))
392    }
393}