Skip to main content

rmux_proto/request/
pane.rs

1use serde::{Deserialize, Deserializer, Serialize};
2use std::path::PathBuf;
3
4use crate::{
5    PaneOutputSubscriptionId, PaneStateSubscriptionId, PaneTarget, PaneTargetRef, ProcessCommand,
6    ResizePaneAdjustment, SessionName, SetOptionMode, 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    /// Whether the new pane should split the full window root (`split-window -f`).
74    #[serde(default)]
75    pub full_size: bool,
76    /// Raw bytes read from client stdin for `split-window -I`.
77    #[serde(default)]
78    pub stdin_payload: Option<Vec<u8>>,
79}
80
81/// Request payload for `split-window` carrying raw tmux target text.
82#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
83pub struct SplitWindowTargetActionRequest {
84    /// Optional raw `-t` target. `None` uses the requester's current pane.
85    #[serde(default)]
86    pub target: Option<String>,
87    /// The requested split direction.
88    pub direction: SplitDirection,
89    /// Whether the new pane is inserted before the target.
90    #[serde(default)]
91    pub before: bool,
92    /// Optional per-spawn environment overrides in `NAME=VALUE` form.
93    #[serde(default)]
94    pub environment: Option<Vec<String>>,
95    /// Legacy optional command argv for the new pane.
96    #[serde(default)]
97    pub command: Option<Vec<String>>,
98    /// Explicit process launch mode for the new pane.
99    #[serde(default)]
100    pub process_command: Option<ProcessCommand>,
101    /// Optional working-directory override for the new pane process.
102    #[serde(default)]
103    pub start_directory: Option<PathBuf>,
104    /// Optional pane-local `remain-on-exit` override applied before spawn.
105    #[serde(default)]
106    pub keep_alive_on_exit: Option<bool>,
107    /// Whether pane selection should stay on the original pane after split.
108    #[serde(default)]
109    pub detached: bool,
110    /// Optional tmux `-l` split size expression.
111    #[serde(default)]
112    pub size: Option<String>,
113    /// Whether an existing zoomed window should remain zoomed after split.
114    #[serde(default)]
115    pub preserve_zoom: bool,
116    /// Whether the new pane should split the full window root.
117    #[serde(default)]
118    pub full_size: bool,
119    /// Raw bytes read from client stdin for `split-window -I`.
120    #[serde(default)]
121    pub stdin_payload: Option<Vec<u8>>,
122}
123
124/// SDK split request that returns the new pane's visible slot and stable id
125/// atomically with the mutation.
126///
127/// This is a capability-gated append-only wire extension. The existing
128/// [`SplitWindowTargetActionRequest`] remains unchanged for CLI callers.
129#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
130pub struct SplitWindowIdentityRequest {
131    /// Complete split action resolved server-side before the mutation.
132    pub action: SplitWindowTargetActionRequest,
133}
134
135impl<'de> Deserialize<'de> for SplitWindowExtRequest {
136    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
137    where
138        D: Deserializer<'de>,
139    {
140        deserializer.deserialize_struct(
141            "SplitWindowExtRequest",
142            &[
143                "target",
144                "direction",
145                "before",
146                "environment",
147                "command",
148                "process_command",
149                "start_directory",
150                "keep_alive_on_exit",
151                "detached",
152                "size",
153                "preserve_zoom",
154                "full_size",
155                "stdin_payload",
156            ],
157            compat::SplitWindowExtRequestVisitor,
158        )
159    }
160}
161
162/// The supported relative directions for `swap-pane`.
163#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
164pub enum SwapPaneDirection {
165    /// Swap the target pane with the next pane.
166    Down,
167    /// Swap the target pane with the previous pane.
168    Up,
169}
170
171/// Request payload for `swap-pane`.
172#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
173pub struct SwapPaneRequest {
174    /// The source pane slot.
175    pub source: PaneTarget,
176    /// The destination pane slot.
177    pub target: PaneTarget,
178    /// The optional relative swap direction for `-D` or `-U`.
179    #[serde(default)]
180    pub direction: Option<SwapPaneDirection>,
181    /// Whether pane selection should remain detached from the swap.
182    pub detached: bool,
183    /// Whether zoomed windows should be restored after the swap (`-Z`).
184    #[serde(default)]
185    pub preserve_zoom: bool,
186}
187
188/// Request payload for `last-pane`.
189#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
190pub struct LastPaneRequest {
191    /// The addressed window.
192    pub target: WindowTarget,
193    /// Whether an existing zoomed window should remain zoomed after selecting.
194    #[serde(default)]
195    pub preserve_zoom: bool,
196    /// Optional input gating to apply to the newly selected pane.
197    #[serde(default)]
198    pub input_disabled: Option<bool>,
199}
200
201impl<'de> Deserialize<'de> for LastPaneRequest {
202    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
203    where
204        D: Deserializer<'de>,
205    {
206        deserializer.deserialize_struct(
207            "LastPaneRequest",
208            &["target", "preserve_zoom", "input_disabled"],
209            compat::LastPaneRequestVisitor,
210        )
211    }
212}
213
214/// Request payload for `join-pane`.
215#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
216pub struct JoinPaneRequest {
217    /// The source pane being moved.
218    pub source: PaneTarget,
219    /// The destination pane the source is joined next to.
220    pub target: PaneTarget,
221    /// The layout direction requested for the join.
222    pub direction: SplitDirection,
223    /// Whether the destination pane should remain inactive after the join.
224    pub detached: bool,
225    /// Whether the source pane should be inserted before the target pane.
226    #[serde(default)]
227    pub before: bool,
228    /// Whether the source pane should span the full window.
229    #[serde(default)]
230    pub full_size: bool,
231    /// Optional requested size for the inserted pane.
232    #[serde(default)]
233    pub size: Option<PaneSplitSize>,
234}
235
236/// Request payload for `break-pane`.
237#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
238pub struct BreakPaneRequest {
239    /// The source pane being moved into its own window.
240    pub source: PaneTarget,
241    /// The optional destination window slot.
242    pub target: Option<WindowTarget>,
243    /// The optional explicit name for the new window.
244    pub name: Option<String>,
245    /// Whether the new window should remain inactive after the break.
246    pub detached: bool,
247    /// Whether the pane should be placed after the destination or current window.
248    #[serde(default)]
249    pub after: bool,
250    /// Whether the pane should be placed before the destination or current window.
251    #[serde(default)]
252    pub before: bool,
253    /// Whether the resulting pane target should be printed.
254    #[serde(default)]
255    pub print_target: bool,
256    /// Optional format used when printing the resulting pane target.
257    #[serde(default)]
258    pub format: Option<String>,
259}
260
261/// Size forms accepted by pane split and join commands.
262#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
263pub enum PaneSplitSize {
264    /// A concrete absolute size in cells.
265    Absolute(u32),
266    /// A percentage of the relevant base size.
267    Percentage(u8),
268}
269
270/// Request payload for `move-pane`.
271#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
272pub struct MovePaneRequest {
273    /// The source pane being moved.
274    pub source: PaneTarget,
275    /// The destination pane the source is joined next to.
276    pub target: PaneTarget,
277    /// The layout direction requested for the move.
278    pub direction: SplitDirection,
279    /// Whether the destination pane should remain inactive after the move.
280    pub detached: bool,
281    /// Whether the source pane should be inserted before the target pane.
282    #[serde(default)]
283    pub before: bool,
284    /// Whether the source pane should span the full window.
285    #[serde(default)]
286    pub full_size: bool,
287    /// Optional requested size for the inserted pane.
288    #[serde(default)]
289    pub size: Option<PaneSplitSize>,
290}
291
292/// Request payload for `kill-pane`.
293#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
294pub struct KillPaneRequest {
295    /// The exact pane target.
296    pub target: PaneTarget,
297    /// Whether all panes except the target should be killed.
298    #[serde(default)]
299    pub kill_all_except: bool,
300}
301
302/// Request payload for `resize-pane`.
303#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
304pub struct ResizePaneRequest {
305    /// The exact pane target.
306    pub target: PaneTarget,
307    /// The semantic resize request.
308    pub adjustment: ResizePaneAdjustment,
309}
310
311/// Request payload for `resize-pane` carrying raw tmux target text.
312#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
313pub struct ResizePaneTargetActionRequest {
314    /// Optional raw `-t` target. `None` uses the requester's current pane.
315    #[serde(default)]
316    pub target: Option<String>,
317    /// The semantic resize request.
318    pub adjustment: ResizePaneAdjustment,
319}
320
321/// Request payload for `display-panes`.
322#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
323pub struct DisplayPanesRequest {
324    /// The exact session whose active window should receive the overlay.
325    pub target: SessionName,
326    /// Optional duration override in milliseconds.
327    #[serde(default)]
328    pub duration_ms: Option<u64>,
329    /// Whether the command should return immediately without waiting for selection.
330    #[serde(default)]
331    pub non_blocking: bool,
332    /// Whether pane selection should not run a follow-up command.
333    #[serde(default)]
334    pub no_command: bool,
335    /// Optional template command executed after pane selection.
336    #[serde(default)]
337    pub template: Option<String>,
338    /// Optional attached client that should receive the pane overlay.
339    #[serde(default)]
340    pub target_client: Option<String>,
341}
342
343/// Request payload for `pipe-pane`.
344#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
345pub struct PipePaneRequest {
346    /// The exact pane target.
347    pub target: PaneTarget,
348    /// Whether pipe output should be written into the pane (`-I`).
349    #[serde(default)]
350    pub stdin: bool,
351    /// Whether pane output should be written into the pipe (`-O`).
352    #[serde(default)]
353    pub stdout: bool,
354    /// Whether an existing pipe should be toggled off without reopening (`-o`).
355    #[serde(default)]
356    pub once: bool,
357    /// The optional shell command. Omitting it closes any existing pipe.
358    #[serde(default)]
359    pub command: Option<String>,
360}
361
362/// Request payload for `respawn-pane`.
363#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
364pub struct RespawnPaneRequest {
365    /// The exact pane target.
366    pub target: PaneTarget,
367    /// Whether a running pane should be killed before respawning (`-k`).
368    #[serde(default)]
369    pub kill: bool,
370    /// Optional working-directory override.
371    #[serde(default)]
372    pub start_directory: Option<PathBuf>,
373    /// Optional per-spawn environment overrides in `NAME=VALUE` form.
374    #[serde(default)]
375    pub environment: Option<Vec<String>>,
376    /// Legacy optional shell command argv. A single argument is executed via
377    /// `$SHELL -c`.
378    #[serde(default)]
379    pub command: Option<Vec<String>>,
380    /// Explicit process launch mode.
381    #[serde(default)]
382    pub process_command: Option<ProcessCommand>,
383}
384
385impl<'de> Deserialize<'de> for RespawnPaneRequest {
386    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
387    where
388        D: Deserializer<'de>,
389    {
390        deserializer.deserialize_struct(
391            "RespawnPaneRequest",
392            &[
393                "target",
394                "kill",
395                "start_directory",
396                "environment",
397                "command",
398                "process_command",
399            ],
400            compat::RespawnPaneRequestVisitor,
401        )
402    }
403}
404
405/// Request payload for `select-pane`.
406#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
407pub struct SelectPaneRequest {
408    /// The exact pane target.
409    pub target: PaneTarget,
410    /// Optional pane title to set without changing the active pane (`-T`).
411    #[serde(default)]
412    pub title: Option<String>,
413    /// Optional pane input state mutation (`select-pane -d` / `-e`).
414    #[serde(default)]
415    pub input_disabled: Option<bool>,
416    /// Whether an existing zoomed window should remain zoomed after selecting.
417    #[serde(default)]
418    pub preserve_zoom: bool,
419    /// Optional pane style to set on the pane-local `window-style` option (`-P`).
420    #[serde(default)]
421    pub style: Option<String>,
422}
423
424impl<'de> Deserialize<'de> for SelectPaneRequest {
425    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
426    where
427        D: Deserializer<'de>,
428    {
429        deserializer.deserialize_struct(
430            "SelectPaneRequest",
431            &[
432                "target",
433                "title",
434                "input_disabled",
435                "preserve_zoom",
436                "style",
437            ],
438            compat::SelectPaneRequestVisitor,
439        )
440    }
441}
442
443/// SDK pane input request that can address a stable pane id.
444#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
445pub struct PaneInputRequest {
446    /// The exact pane target or stable pane id.
447    pub target: PaneTargetRef,
448    /// Text or key tokens to send.
449    pub keys: Vec<String>,
450    /// Whether tokens should be written literally instead of interpreted as
451    /// tmux-compatible key names.
452    #[serde(default)]
453    pub literal: bool,
454}
455
456/// SDK pane input broadcast request with stable pane-id targeting.
457#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
458pub struct PaneBroadcastInputRequest {
459    /// Pane targets addressed in caller order.
460    pub targets: Vec<PaneTargetRef>,
461    /// Text or key tokens to send to each pane.
462    pub keys: Vec<String>,
463    /// Whether tokens should be written literally instead of interpreted as
464    /// tmux-compatible key names.
465    #[serde(default)]
466    pub literal: bool,
467}
468
469/// SDK resize request that can address a stable pane id.
470#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
471pub struct PaneResizeRequest {
472    /// The exact pane target or stable pane id.
473    pub target: PaneTargetRef,
474    /// The semantic resize request.
475    pub adjustment: ResizePaneAdjustment,
476}
477
478/// SDK kill request that can address a stable pane id.
479#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
480pub struct PaneKillRequest {
481    /// The exact pane target or stable pane id.
482    pub target: PaneTargetRef,
483    /// Whether all panes except the target should be killed.
484    #[serde(default)]
485    pub kill_all_except: bool,
486}
487
488/// SDK respawn request that can address a stable pane id.
489#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
490pub struct PaneRespawnRequest {
491    /// The exact pane target or stable pane id.
492    pub target: PaneTargetRef,
493    /// Whether a running pane should be killed before respawning.
494    #[serde(default)]
495    pub kill: bool,
496    /// Optional working-directory override.
497    #[serde(default)]
498    pub start_directory: Option<PathBuf>,
499    /// Optional per-spawn environment overrides in `NAME=VALUE` form.
500    #[serde(default)]
501    pub environment: Option<Vec<String>>,
502    /// Legacy optional shell command argv. A single argument is executed via
503    /// `$SHELL -c`.
504    #[serde(default)]
505    pub command: Option<Vec<String>>,
506    /// Explicit process launch mode.
507    #[serde(default)]
508    pub process_command: Option<ProcessCommand>,
509    /// Optional pane-local `remain-on-exit` override applied before respawn.
510    #[serde(default)]
511    pub keep_alive_on_exit: Option<bool>,
512}
513
514/// SDK snapshot request that can address a stable pane id.
515#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
516pub struct PaneSnapshotRefRequest {
517    /// The exact pane target or stable pane id.
518    pub target: PaneTargetRef,
519}
520
521/// SDK select/title request that can address a stable pane id.
522#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
523pub struct PaneSelectRequest {
524    /// The exact pane target or stable pane id.
525    pub target: PaneTargetRef,
526    /// Optional pane title to set without changing the active pane.
527    #[serde(default)]
528    pub title: Option<String>,
529}
530
531/// SDK pane option mutation request that can address a stable pane id.
532#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
533pub struct PaneOptionSetRequest {
534    /// The exact pane target or stable pane id.
535    pub target: PaneTargetRef,
536    /// The tmux-style option name.
537    pub name: String,
538    /// The value to set. `None` is valid only when `unset` is true or when the
539    /// option type supports value-less toggles.
540    #[serde(default)]
541    pub value: Option<String>,
542    /// The scalar/array mutation mode.
543    pub mode: SetOptionMode,
544    /// Whether to remove the pane-local explicit value instead of setting it.
545    #[serde(default)]
546    pub unset: bool,
547}
548
549/// SDK pane option lookup request that can address a stable pane id.
550#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
551pub struct PaneOptionGetRequest {
552    /// The exact pane target or stable pane id.
553    pub target: PaneTargetRef,
554    /// The tmux-style option name.
555    pub name: String,
556}
557
558/// SDK pane-state subscription request that can address a stable pane id.
559#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
560pub struct SubscribePaneStateRequest {
561    /// The exact pane target or stable pane id.
562    pub target: PaneTargetRef,
563    /// Whether the initial snapshot and stream should include title changes.
564    #[serde(default = "default_include_pane_state_title")]
565    pub include_title: bool,
566    /// Whether the initial snapshot and stream should include pane options.
567    #[serde(default = "default_include_pane_state_options")]
568    pub include_options: bool,
569    /// Whether the initial snapshot and stream should include foreground state.
570    #[serde(default)]
571    pub include_foreground: bool,
572}
573
574/// SDK pane-state cursor request.
575#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
576pub struct PaneStateCursorRequest {
577    /// The subscription to poll.
578    pub subscription_id: PaneStateSubscriptionId,
579    /// Return records whose revision is strictly greater than this value.
580    pub after_revision: u64,
581    /// Whether the server may hold the request until a new record appears.
582    #[serde(default)]
583    pub wait: bool,
584    /// Optional per-response event cap.
585    #[serde(default)]
586    pub max_events: Option<u16>,
587}
588
589/// SDK pane-state unsubscription request.
590#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
591pub struct UnsubscribePaneStateRequest {
592    /// The subscription to remove.
593    pub subscription_id: PaneStateSubscriptionId,
594}
595
596/// SDK foreground-state request that can address a stable pane id.
597#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
598pub struct PaneForegroundStateRequest {
599    /// The exact pane target or stable pane id.
600    pub target: PaneTargetRef,
601}
602
603const fn default_include_pane_state_title() -> bool {
604    true
605}
606
607const fn default_include_pane_state_options() -> bool {
608    true
609}
610
611/// Direction used by `select-pane -U/-D/-L/-R`.
612#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
613pub enum SelectPaneDirection {
614    /// Select the pane above the target pane.
615    Up,
616    /// Select the pane below the target pane.
617    Down,
618    /// Select the pane to the left of the target pane.
619    Left,
620    /// Select the pane to the right of the target pane.
621    Right,
622}
623
624/// Request payload for directional `select-pane`.
625#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
626pub struct SelectPaneAdjacentRequest {
627    /// The pane used as the directional anchor.
628    pub target: PaneTarget,
629    /// The requested adjacent-pane direction.
630    pub direction: SelectPaneDirection,
631    /// Whether an existing zoomed window should remain zoomed after selecting.
632    #[serde(default)]
633    pub preserve_zoom: bool,
634}
635
636impl<'de> Deserialize<'de> for SelectPaneAdjacentRequest {
637    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
638    where
639        D: Deserializer<'de>,
640    {
641        deserializer.deserialize_struct(
642            "SelectPaneAdjacentRequest",
643            &["target", "direction", "preserve_zoom"],
644            compat::SelectPaneAdjacentRequestVisitor,
645        )
646    }
647}
648
649/// Request payload for `select-pane -m` and `select-pane -M`.
650#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
651pub struct SelectPaneMarkRequest {
652    /// The pane target used to resolve the current session/window context.
653    pub target: PaneTarget,
654    /// Whether to clear the existing marked pane instead of toggling the target.
655    pub clear: bool,
656    /// Optional pane title to set while applying the mark operation (`-T`).
657    #[serde(default)]
658    pub title: Option<String>,
659}
660
661/// Request payload for the daemon-backed pane snapshot endpoint.
662///
663/// Unlike [`CapturePaneRequest`](crate::CapturePaneRequest), which returns a
664/// pre-rendered byte stream of the visible viewport, this request asks the
665/// daemon to expose its live in-memory grid as structured cells. The daemon
666/// reads the cells directly from the rmux-core screen that is fed by its
667/// crate-private terminal parser, so there is no `String::from_utf8_lossy`
668/// reconstruction step on either side of the wire.
669#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
670pub struct PaneSnapshotRequest {
671    /// The exact pane target whose visible viewport should be captured.
672    pub target: PaneTarget,
673}
674
675/// Starting position for a pane-output subscription cursor.
676#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
677pub enum PaneOutputSubscriptionStart {
678    /// Start after the newest output currently retained by the pane.
679    Now,
680    /// Start at the oldest retained output event.
681    Oldest,
682}
683
684/// Request payload for subscribing to live pane-output events.
685#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
686pub struct SubscribePaneOutputRequest {
687    /// The exact pane target whose output should be subscribed.
688    pub target: PaneTarget,
689    /// The initial cursor position.
690    pub start: PaneOutputSubscriptionStart,
691}
692
693/// Request payload for subscribing to live pane-output events by slot or id.
694#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
695pub struct SubscribePaneOutputRefRequest {
696    /// The exact pane target or stable pane id whose output should be
697    /// subscribed.
698    pub target: PaneTargetRef,
699    /// The initial cursor position.
700    pub start: PaneOutputSubscriptionStart,
701}
702
703/// Request payload for unsubscribing from live pane-output events.
704#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
705pub struct UnsubscribePaneOutputRequest {
706    /// The subscription to remove.
707    pub subscription_id: PaneOutputSubscriptionId,
708}
709
710/// Request payload for polling a pane-output subscription cursor.
711#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
712pub struct PaneOutputCursorRequest {
713    /// The subscription whose cursor should be polled.
714    pub subscription_id: PaneOutputSubscriptionId,
715    /// Optional caller-requested event cap. The server clamps this to the
716    /// recorded v1 default batch limit.
717    #[serde(default)]
718    pub max_events: Option<u16>,
719}
720
721/// Projection selected for a recoverable pane stream.
722#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
723#[non_exhaustive]
724pub enum PaneStreamMode {
725    /// Raw terminal bytes with automatic in-band renderer rebases.
726    Raw,
727    /// Authoritative structured viewport frames.
728    Surface,
729}
730
731/// Request payload for opening a recoverable pane stream.
732#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
733pub struct SubscribePaneStreamRequest {
734    /// Stable pane identity or pane slot resolved atomically by the daemon.
735    pub target: PaneTargetRef,
736    /// Requested projection.
737    pub mode: PaneStreamMode,
738    /// Include a typed snapshot with raw rebases.
739    ///
740    /// Raw emulator consumers normally leave this false; inspection tools can
741    /// request it without forcing every rebase to carry duplicate state.
742    pub include_snapshot: bool,
743}
744
745/// Request payload for polling a recoverable pane stream.
746#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
747pub struct PaneStreamCursorRequest {
748    /// Opaque stream subscription allocated by the daemon.
749    pub subscription_id: PaneOutputSubscriptionId,
750    /// Optional caller cap, clamped to the daemon subscription limit.
751    #[serde(default)]
752    pub max_events: Option<u16>,
753}
754
755/// Request payload for closing a recoverable pane stream.
756#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
757pub struct UnsubscribePaneStreamRequest {
758    /// Opaque stream subscription allocated by the daemon.
759    pub subscription_id: PaneOutputSubscriptionId,
760}
761
762/// Request payload for `send-keys`.
763#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
764pub struct SendKeysRequest {
765    /// The exact pane target.
766    pub target: PaneTarget,
767    /// Key tokens in left-to-right order.
768    pub keys: Vec<String>,
769}
770
771/// Extended request payload for `send-keys`.
772#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
773pub struct SendKeysExtRequest {
774    /// The optional explicit pane target.
775    pub target: Option<PaneTarget>,
776    /// Key tokens in left-to-right order.
777    pub keys: Vec<String>,
778    /// Whether tmux format expansion should be applied to each token first.
779    pub expand_formats: bool,
780    /// Whether each token should be interpreted as a hexadecimal byte value.
781    pub hex: bool,
782    /// Whether tokens should be sent as literal bytes instead of key names.
783    #[serde(default)]
784    pub literal: bool,
785    /// Whether keys should be dispatched through the client's key table.
786    pub dispatch_key_table: bool,
787    /// Whether tokens describe copy-mode commands.
788    pub copy_mode_command: bool,
789    /// Whether the payload should be treated as a mouse event.
790    pub forward_mouse_event: bool,
791    /// Whether the target terminal should be reset before sending keys.
792    pub reset_terminal: bool,
793    /// Optional tmux repeat count for command or key dispatch.
794    pub repeat_count: Option<usize>,
795}
796
797/// Further-extended request payload for `send-keys -c`.
798///
799/// This is intentionally separate from [`SendKeysExtRequest`] so the original
800/// bincode field order remains wire-compatible with older clients and daemons.
801#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
802pub struct SendKeysExt2Request {
803    /// The optional explicit pane target.
804    pub target: Option<PaneTarget>,
805    /// Key tokens in left-to-right order.
806    pub keys: Vec<String>,
807    /// Whether tmux format expansion should be applied to each token first.
808    pub expand_formats: bool,
809    /// Whether each token should be interpreted as a hexadecimal byte value.
810    pub hex: bool,
811    /// Whether tokens should be sent as literal bytes instead of key names.
812    #[serde(default)]
813    pub literal: bool,
814    /// Whether keys should be dispatched through the client's key table.
815    pub dispatch_key_table: bool,
816    /// Whether tokens describe copy-mode commands.
817    pub copy_mode_command: bool,
818    /// Whether the payload should be treated as a mouse event.
819    pub forward_mouse_event: bool,
820    /// Whether the target terminal should be reset before sending keys.
821    pub reset_terminal: bool,
822    /// Optional tmux repeat count for command or key dispatch.
823    pub repeat_count: Option<usize>,
824    /// Optional target client used for current-pane resolution and client key dispatch.
825    pub target_client: Option<String>,
826}