Skip to main content

rmux_proto/request/
pane.rs

1use serde::{Deserialize, Deserializer, Serialize};
2use std::path::PathBuf;
3
4use crate::{
5    PaneOutputSubscriptionId, PaneTarget, PaneTargetRef, ProcessCommand, ResizePaneAdjustment,
6    SessionName, SplitDirection, WindowTarget,
7};
8
9#[path = "pane/compat.rs"]
10mod compat;
11
12/// Target forms accepted by `split-window`.
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14pub enum SplitWindowTarget {
15    /// Splits the active pane in the addressed session.
16    Session(SessionName),
17    /// Splits the addressed pane directly.
18    Pane(PaneTarget),
19}
20
21/// Request payload for `split-window`.
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23pub struct SplitWindowRequest {
24    /// The exact split target.
25    pub target: SplitWindowTarget,
26    /// The requested split direction.
27    pub direction: SplitDirection,
28    /// Whether the new pane is inserted *before* the target on the chosen
29    /// axis (tmux `-b`). Default `false` puts the new pane after the target.
30    #[serde(default)]
31    pub before: bool,
32    /// Optional per-spawn environment overrides in `NAME=VALUE` form.
33    #[serde(default)]
34    pub environment: Option<Vec<String>>,
35}
36
37/// Extended request payload for `split-window`.
38#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
39pub struct SplitWindowExtRequest {
40    /// The exact split target.
41    pub target: SplitWindowTarget,
42    /// The requested split direction.
43    pub direction: SplitDirection,
44    /// Whether the new pane is inserted *before* the target on the chosen
45    /// axis (tmux `-b`). Default `false` puts the new pane after the target.
46    #[serde(default)]
47    pub before: bool,
48    /// Optional per-spawn environment overrides in `NAME=VALUE` form.
49    #[serde(default)]
50    pub environment: Option<Vec<String>>,
51    /// Legacy optional command argv for the new pane. A single argument runs
52    /// via `$SHELL -c`.
53    #[serde(default)]
54    pub command: Option<Vec<String>>,
55    /// Explicit process launch mode for the new pane.
56    #[serde(default)]
57    pub process_command: Option<ProcessCommand>,
58    /// Optional working-directory override for the new pane process.
59    #[serde(default)]
60    pub start_directory: Option<PathBuf>,
61    /// Optional pane-local `remain-on-exit` override applied before spawn.
62    #[serde(default)]
63    pub keep_alive_on_exit: Option<bool>,
64    /// Whether pane selection should stay on the original pane after split.
65    #[serde(default)]
66    pub detached: bool,
67    /// Optional tmux `-l` split size expression.
68    #[serde(default)]
69    pub size: Option<String>,
70    /// Whether an existing zoomed window should remain zoomed after split.
71    #[serde(default)]
72    pub preserve_zoom: bool,
73}
74
75impl<'de> Deserialize<'de> for SplitWindowExtRequest {
76    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
77    where
78        D: Deserializer<'de>,
79    {
80        deserializer.deserialize_struct(
81            "SplitWindowExtRequest",
82            &[
83                "target",
84                "direction",
85                "before",
86                "environment",
87                "command",
88                "process_command",
89                "start_directory",
90                "keep_alive_on_exit",
91                "detached",
92                "size",
93                "preserve_zoom",
94            ],
95            compat::SplitWindowExtRequestVisitor,
96        )
97    }
98}
99
100/// The supported relative directions for `swap-pane`.
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
102pub enum SwapPaneDirection {
103    /// Swap the target pane with the next pane.
104    Down,
105    /// Swap the target pane with the previous pane.
106    Up,
107}
108
109/// Request payload for `swap-pane`.
110#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
111pub struct SwapPaneRequest {
112    /// The source pane slot.
113    pub source: PaneTarget,
114    /// The destination pane slot.
115    pub target: PaneTarget,
116    /// The optional relative swap direction for `-D` or `-U`.
117    #[serde(default)]
118    pub direction: Option<SwapPaneDirection>,
119    /// Whether pane selection should remain detached from the swap.
120    pub detached: bool,
121    /// Whether zoomed windows should be restored after the swap (`-Z`).
122    #[serde(default)]
123    pub preserve_zoom: bool,
124}
125
126/// Request payload for `last-pane`.
127#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
128pub struct LastPaneRequest {
129    /// The addressed window.
130    pub target: WindowTarget,
131}
132
133/// Request payload for `join-pane`.
134#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
135pub struct JoinPaneRequest {
136    /// The source pane being moved.
137    pub source: PaneTarget,
138    /// The destination pane the source is joined next to.
139    pub target: PaneTarget,
140    /// The layout direction requested for the join.
141    pub direction: SplitDirection,
142    /// Whether the destination pane should remain inactive after the join.
143    pub detached: bool,
144    /// Whether the source pane should be inserted before the target pane.
145    #[serde(default)]
146    pub before: bool,
147    /// Whether the source pane should span the full window.
148    #[serde(default)]
149    pub full_size: bool,
150    /// Optional requested size for the inserted pane.
151    #[serde(default)]
152    pub size: Option<PaneSplitSize>,
153}
154
155/// Request payload for `break-pane`.
156#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
157pub struct BreakPaneRequest {
158    /// The source pane being moved into its own window.
159    pub source: PaneTarget,
160    /// The optional destination window slot.
161    pub target: Option<WindowTarget>,
162    /// The optional explicit name for the new window.
163    pub name: Option<String>,
164    /// Whether the new window should remain inactive after the break.
165    pub detached: bool,
166    /// Whether the pane should be placed after the destination or current window.
167    #[serde(default)]
168    pub after: bool,
169    /// Whether the pane should be placed before the destination or current window.
170    #[serde(default)]
171    pub before: bool,
172    /// Whether the resulting pane target should be printed.
173    #[serde(default)]
174    pub print_target: bool,
175    /// Optional format used when printing the resulting pane target.
176    #[serde(default)]
177    pub format: Option<String>,
178}
179
180/// Size forms accepted by pane split and join commands.
181#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
182pub enum PaneSplitSize {
183    /// A concrete absolute size in cells.
184    Absolute(u32),
185    /// A percentage of the relevant base size.
186    Percentage(u8),
187}
188
189/// Request payload for `move-pane`.
190#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
191pub struct MovePaneRequest {
192    /// The source pane being moved.
193    pub source: PaneTarget,
194    /// The destination pane the source is joined next to.
195    pub target: PaneTarget,
196    /// The layout direction requested for the move.
197    pub direction: SplitDirection,
198    /// Whether the destination pane should remain inactive after the move.
199    pub detached: bool,
200    /// Whether the source pane should be inserted before the target pane.
201    #[serde(default)]
202    pub before: bool,
203    /// Whether the source pane should span the full window.
204    #[serde(default)]
205    pub full_size: bool,
206    /// Optional requested size for the inserted pane.
207    #[serde(default)]
208    pub size: Option<PaneSplitSize>,
209}
210
211/// Request payload for `kill-pane`.
212#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
213pub struct KillPaneRequest {
214    /// The exact pane target.
215    pub target: PaneTarget,
216    /// Whether all panes except the target should be killed.
217    #[serde(default)]
218    pub kill_all_except: bool,
219}
220
221/// Request payload for `resize-pane`.
222#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
223pub struct ResizePaneRequest {
224    /// The exact pane target.
225    pub target: PaneTarget,
226    /// The semantic resize request.
227    pub adjustment: ResizePaneAdjustment,
228}
229
230/// Request payload for `display-panes`.
231#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
232pub struct DisplayPanesRequest {
233    /// The exact session whose active window should receive the overlay.
234    pub target: SessionName,
235    /// Optional duration override in milliseconds.
236    #[serde(default)]
237    pub duration_ms: Option<u64>,
238    /// Whether the command should return immediately without waiting for selection.
239    #[serde(default)]
240    pub non_blocking: bool,
241    /// Whether pane selection should not run a follow-up command.
242    #[serde(default)]
243    pub no_command: bool,
244    /// Optional template command executed after pane selection.
245    #[serde(default)]
246    pub template: Option<String>,
247}
248
249/// Request payload for `pipe-pane`.
250#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
251pub struct PipePaneRequest {
252    /// The exact pane target.
253    pub target: PaneTarget,
254    /// Whether pipe output should be written into the pane (`-I`).
255    #[serde(default)]
256    pub stdin: bool,
257    /// Whether pane output should be written into the pipe (`-O`).
258    #[serde(default)]
259    pub stdout: bool,
260    /// Whether an existing pipe should be toggled off without reopening (`-o`).
261    #[serde(default)]
262    pub once: bool,
263    /// The optional shell command. Omitting it closes any existing pipe.
264    #[serde(default)]
265    pub command: Option<String>,
266}
267
268/// Request payload for `respawn-pane`.
269#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
270pub struct RespawnPaneRequest {
271    /// The exact pane target.
272    pub target: PaneTarget,
273    /// Whether a running pane should be killed before respawning (`-k`).
274    #[serde(default)]
275    pub kill: bool,
276    /// Optional working-directory override.
277    #[serde(default)]
278    pub start_directory: Option<PathBuf>,
279    /// Optional per-spawn environment overrides in `NAME=VALUE` form.
280    #[serde(default)]
281    pub environment: Option<Vec<String>>,
282    /// Legacy optional shell command argv. A single argument is executed via
283    /// `$SHELL -c`.
284    #[serde(default)]
285    pub command: Option<Vec<String>>,
286    /// Explicit process launch mode.
287    #[serde(default)]
288    pub process_command: Option<ProcessCommand>,
289}
290
291impl<'de> Deserialize<'de> for RespawnPaneRequest {
292    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
293    where
294        D: Deserializer<'de>,
295    {
296        deserializer.deserialize_struct(
297            "RespawnPaneRequest",
298            &[
299                "target",
300                "kill",
301                "start_directory",
302                "environment",
303                "command",
304                "process_command",
305            ],
306            compat::RespawnPaneRequestVisitor,
307        )
308    }
309}
310
311/// Request payload for `select-pane`.
312#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
313pub struct SelectPaneRequest {
314    /// The exact pane target.
315    pub target: PaneTarget,
316    /// Optional pane title to set without changing the active pane (`-T`).
317    #[serde(default)]
318    pub title: Option<String>,
319}
320
321/// SDK pane input request that can address a stable pane id.
322#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
323pub struct PaneInputRequest {
324    /// The exact pane target or stable pane id.
325    pub target: PaneTargetRef,
326    /// Text or key tokens to send.
327    pub keys: Vec<String>,
328    /// Whether tokens should be written literally instead of interpreted as
329    /// tmux-compatible key names.
330    #[serde(default)]
331    pub literal: bool,
332}
333
334/// SDK pane input broadcast request with stable pane-id targeting.
335#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
336pub struct PaneBroadcastInputRequest {
337    /// Pane targets addressed in caller order.
338    pub targets: Vec<PaneTargetRef>,
339    /// Text or key tokens to send to each pane.
340    pub keys: Vec<String>,
341    /// Whether tokens should be written literally instead of interpreted as
342    /// tmux-compatible key names.
343    #[serde(default)]
344    pub literal: bool,
345}
346
347/// SDK resize request that can address a stable pane id.
348#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
349pub struct PaneResizeRequest {
350    /// The exact pane target or stable pane id.
351    pub target: PaneTargetRef,
352    /// The semantic resize request.
353    pub adjustment: ResizePaneAdjustment,
354}
355
356/// SDK kill request that can address a stable pane id.
357#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
358pub struct PaneKillRequest {
359    /// The exact pane target or stable pane id.
360    pub target: PaneTargetRef,
361    /// Whether all panes except the target should be killed.
362    #[serde(default)]
363    pub kill_all_except: bool,
364}
365
366/// SDK respawn request that can address a stable pane id.
367#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
368pub struct PaneRespawnRequest {
369    /// The exact pane target or stable pane id.
370    pub target: PaneTargetRef,
371    /// Whether a running pane should be killed before respawning.
372    #[serde(default)]
373    pub kill: bool,
374    /// Optional working-directory override.
375    #[serde(default)]
376    pub start_directory: Option<PathBuf>,
377    /// Optional per-spawn environment overrides in `NAME=VALUE` form.
378    #[serde(default)]
379    pub environment: Option<Vec<String>>,
380    /// Legacy optional shell command argv. A single argument is executed via
381    /// `$SHELL -c`.
382    #[serde(default)]
383    pub command: Option<Vec<String>>,
384    /// Explicit process launch mode.
385    #[serde(default)]
386    pub process_command: Option<ProcessCommand>,
387    /// Optional pane-local `remain-on-exit` override applied before respawn.
388    #[serde(default)]
389    pub keep_alive_on_exit: Option<bool>,
390}
391
392/// SDK snapshot request that can address a stable pane id.
393#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
394pub struct PaneSnapshotRefRequest {
395    /// The exact pane target or stable pane id.
396    pub target: PaneTargetRef,
397}
398
399/// SDK select/title request that can address a stable pane id.
400#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
401pub struct PaneSelectRequest {
402    /// The exact pane target or stable pane id.
403    pub target: PaneTargetRef,
404    /// Optional pane title to set without changing the active pane.
405    #[serde(default)]
406    pub title: Option<String>,
407}
408
409/// Direction used by `select-pane -U/-D/-L/-R`.
410#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
411pub enum SelectPaneDirection {
412    /// Select the pane above the target pane.
413    Up,
414    /// Select the pane below the target pane.
415    Down,
416    /// Select the pane to the left of the target pane.
417    Left,
418    /// Select the pane to the right of the target pane.
419    Right,
420}
421
422/// Request payload for directional `select-pane`.
423#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
424pub struct SelectPaneAdjacentRequest {
425    /// The pane used as the directional anchor.
426    pub target: PaneTarget,
427    /// The requested adjacent-pane direction.
428    pub direction: SelectPaneDirection,
429}
430
431/// Request payload for `select-pane -m` and `select-pane -M`.
432#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
433pub struct SelectPaneMarkRequest {
434    /// The pane target used to resolve the current session/window context.
435    pub target: PaneTarget,
436    /// Whether to clear the existing marked pane instead of toggling the target.
437    pub clear: bool,
438    /// Optional pane title to set while applying the mark operation (`-T`).
439    #[serde(default)]
440    pub title: Option<String>,
441}
442
443/// Request payload for the daemon-backed pane snapshot endpoint.
444///
445/// Unlike [`CapturePaneRequest`](crate::CapturePaneRequest), which returns a
446/// pre-rendered byte stream of the visible viewport, this request asks the
447/// daemon to expose its live in-memory grid as structured cells. The daemon
448/// reads the cells directly from the rmux-core screen that is fed by its
449/// crate-private terminal parser, so there is no `String::from_utf8_lossy`
450/// reconstruction step on either side of the wire.
451#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
452pub struct PaneSnapshotRequest {
453    /// The exact pane target whose visible viewport should be captured.
454    pub target: PaneTarget,
455}
456
457/// Starting position for a pane-output subscription cursor.
458#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
459pub enum PaneOutputSubscriptionStart {
460    /// Start after the newest output currently retained by the pane.
461    Now,
462    /// Start at the oldest retained output event.
463    Oldest,
464}
465
466/// Request payload for subscribing to live pane-output events.
467#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
468pub struct SubscribePaneOutputRequest {
469    /// The exact pane target whose output should be subscribed.
470    pub target: PaneTarget,
471    /// The initial cursor position.
472    pub start: PaneOutputSubscriptionStart,
473}
474
475/// Request payload for subscribing to live pane-output events by slot or id.
476#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
477pub struct SubscribePaneOutputRefRequest {
478    /// The exact pane target or stable pane id whose output should be
479    /// subscribed.
480    pub target: PaneTargetRef,
481    /// The initial cursor position.
482    pub start: PaneOutputSubscriptionStart,
483}
484
485/// Request payload for unsubscribing from live pane-output events.
486#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
487pub struct UnsubscribePaneOutputRequest {
488    /// The subscription to remove.
489    pub subscription_id: PaneOutputSubscriptionId,
490}
491
492/// Request payload for polling a pane-output subscription cursor.
493#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
494pub struct PaneOutputCursorRequest {
495    /// The subscription whose cursor should be polled.
496    pub subscription_id: PaneOutputSubscriptionId,
497    /// Optional caller-requested event cap. The server clamps this to the
498    /// recorded v1 default batch limit.
499    #[serde(default)]
500    pub max_events: Option<u16>,
501}
502
503/// Request payload for `send-keys`.
504#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
505pub struct SendKeysRequest {
506    /// The exact pane target.
507    pub target: PaneTarget,
508    /// Key tokens in left-to-right order.
509    pub keys: Vec<String>,
510}
511
512/// Extended request payload for `send-keys`.
513#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
514pub struct SendKeysExtRequest {
515    /// The optional explicit pane target.
516    pub target: Option<PaneTarget>,
517    /// Key tokens in left-to-right order.
518    pub keys: Vec<String>,
519    /// Whether tmux format expansion should be applied to each token first.
520    pub expand_formats: bool,
521    /// Whether each token should be interpreted as a hexadecimal byte value.
522    pub hex: bool,
523    /// Whether tokens should be sent as literal bytes instead of key names.
524    #[serde(default)]
525    pub literal: bool,
526    /// Whether keys should be dispatched through the client's key table.
527    pub dispatch_key_table: bool,
528    /// Whether tokens describe copy-mode commands.
529    pub copy_mode_command: bool,
530    /// Whether the payload should be treated as a mouse event.
531    pub forward_mouse_event: bool,
532    /// Whether the target terminal should be reset before sending keys.
533    pub reset_terminal: bool,
534    /// Optional tmux repeat count for command or key dispatch.
535    pub repeat_count: Option<usize>,
536}
537
538/// Further-extended request payload for `send-keys -c`.
539///
540/// This is intentionally separate from [`SendKeysExtRequest`] so the original
541/// bincode field order remains wire-compatible with older clients and daemons.
542#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
543pub struct SendKeysExt2Request {
544    /// The optional explicit pane target.
545    pub target: Option<PaneTarget>,
546    /// Key tokens in left-to-right order.
547    pub keys: Vec<String>,
548    /// Whether tmux format expansion should be applied to each token first.
549    pub expand_formats: bool,
550    /// Whether each token should be interpreted as a hexadecimal byte value.
551    pub hex: bool,
552    /// Whether tokens should be sent as literal bytes instead of key names.
553    #[serde(default)]
554    pub literal: bool,
555    /// Whether keys should be dispatched through the client's key table.
556    pub dispatch_key_table: bool,
557    /// Whether tokens describe copy-mode commands.
558    pub copy_mode_command: bool,
559    /// Whether the payload should be treated as a mouse event.
560    pub forward_mouse_event: bool,
561    /// Whether the target terminal should be reset before sending keys.
562    pub reset_terminal: bool,
563    /// Optional tmux repeat count for command or key dispatch.
564    pub repeat_count: Option<usize>,
565    /// Optional target client used for current-pane resolution and client key dispatch.
566    pub target_client: Option<String>,
567}