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    /// 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
124impl<'de> Deserialize<'de> for SplitWindowExtRequest {
125    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
126    where
127        D: Deserializer<'de>,
128    {
129        deserializer.deserialize_struct(
130            "SplitWindowExtRequest",
131            &[
132                "target",
133                "direction",
134                "before",
135                "environment",
136                "command",
137                "process_command",
138                "start_directory",
139                "keep_alive_on_exit",
140                "detached",
141                "size",
142                "preserve_zoom",
143                "full_size",
144                "stdin_payload",
145            ],
146            compat::SplitWindowExtRequestVisitor,
147        )
148    }
149}
150
151/// The supported relative directions for `swap-pane`.
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
153pub enum SwapPaneDirection {
154    /// Swap the target pane with the next pane.
155    Down,
156    /// Swap the target pane with the previous pane.
157    Up,
158}
159
160/// Request payload for `swap-pane`.
161#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
162pub struct SwapPaneRequest {
163    /// The source pane slot.
164    pub source: PaneTarget,
165    /// The destination pane slot.
166    pub target: PaneTarget,
167    /// The optional relative swap direction for `-D` or `-U`.
168    #[serde(default)]
169    pub direction: Option<SwapPaneDirection>,
170    /// Whether pane selection should remain detached from the swap.
171    pub detached: bool,
172    /// Whether zoomed windows should be restored after the swap (`-Z`).
173    #[serde(default)]
174    pub preserve_zoom: bool,
175}
176
177/// Request payload for `last-pane`.
178#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
179pub struct LastPaneRequest {
180    /// The addressed window.
181    pub target: WindowTarget,
182    /// Whether an existing zoomed window should remain zoomed after selecting.
183    #[serde(default)]
184    pub preserve_zoom: bool,
185    /// Optional input gating to apply to the newly selected pane.
186    #[serde(default)]
187    pub input_disabled: Option<bool>,
188}
189
190impl<'de> Deserialize<'de> for LastPaneRequest {
191    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
192    where
193        D: Deserializer<'de>,
194    {
195        deserializer.deserialize_struct(
196            "LastPaneRequest",
197            &["target", "preserve_zoom", "input_disabled"],
198            compat::LastPaneRequestVisitor,
199        )
200    }
201}
202
203/// Request payload for `join-pane`.
204#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
205pub struct JoinPaneRequest {
206    /// The source pane being moved.
207    pub source: PaneTarget,
208    /// The destination pane the source is joined next to.
209    pub target: PaneTarget,
210    /// The layout direction requested for the join.
211    pub direction: SplitDirection,
212    /// Whether the destination pane should remain inactive after the join.
213    pub detached: bool,
214    /// Whether the source pane should be inserted before the target pane.
215    #[serde(default)]
216    pub before: bool,
217    /// Whether the source pane should span the full window.
218    #[serde(default)]
219    pub full_size: bool,
220    /// Optional requested size for the inserted pane.
221    #[serde(default)]
222    pub size: Option<PaneSplitSize>,
223}
224
225/// Request payload for `break-pane`.
226#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
227pub struct BreakPaneRequest {
228    /// The source pane being moved into its own window.
229    pub source: PaneTarget,
230    /// The optional destination window slot.
231    pub target: Option<WindowTarget>,
232    /// The optional explicit name for the new window.
233    pub name: Option<String>,
234    /// Whether the new window should remain inactive after the break.
235    pub detached: bool,
236    /// Whether the pane should be placed after the destination or current window.
237    #[serde(default)]
238    pub after: bool,
239    /// Whether the pane should be placed before the destination or current window.
240    #[serde(default)]
241    pub before: bool,
242    /// Whether the resulting pane target should be printed.
243    #[serde(default)]
244    pub print_target: bool,
245    /// Optional format used when printing the resulting pane target.
246    #[serde(default)]
247    pub format: Option<String>,
248}
249
250/// Size forms accepted by pane split and join commands.
251#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
252pub enum PaneSplitSize {
253    /// A concrete absolute size in cells.
254    Absolute(u32),
255    /// A percentage of the relevant base size.
256    Percentage(u8),
257}
258
259/// Request payload for `move-pane`.
260#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
261pub struct MovePaneRequest {
262    /// The source pane being moved.
263    pub source: PaneTarget,
264    /// The destination pane the source is joined next to.
265    pub target: PaneTarget,
266    /// The layout direction requested for the move.
267    pub direction: SplitDirection,
268    /// Whether the destination pane should remain inactive after the move.
269    pub detached: bool,
270    /// Whether the source pane should be inserted before the target pane.
271    #[serde(default)]
272    pub before: bool,
273    /// Whether the source pane should span the full window.
274    #[serde(default)]
275    pub full_size: bool,
276    /// Optional requested size for the inserted pane.
277    #[serde(default)]
278    pub size: Option<PaneSplitSize>,
279}
280
281/// Request payload for `kill-pane`.
282#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
283pub struct KillPaneRequest {
284    /// The exact pane target.
285    pub target: PaneTarget,
286    /// Whether all panes except the target should be killed.
287    #[serde(default)]
288    pub kill_all_except: bool,
289}
290
291/// Request payload for `resize-pane`.
292#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
293pub struct ResizePaneRequest {
294    /// The exact pane target.
295    pub target: PaneTarget,
296    /// The semantic resize request.
297    pub adjustment: ResizePaneAdjustment,
298}
299
300/// Request payload for `resize-pane` carrying raw tmux target text.
301#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
302pub struct ResizePaneTargetActionRequest {
303    /// Optional raw `-t` target. `None` uses the requester's current pane.
304    #[serde(default)]
305    pub target: Option<String>,
306    /// The semantic resize request.
307    pub adjustment: ResizePaneAdjustment,
308}
309
310/// Request payload for `display-panes`.
311#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
312pub struct DisplayPanesRequest {
313    /// The exact session whose active window should receive the overlay.
314    pub target: SessionName,
315    /// Optional duration override in milliseconds.
316    #[serde(default)]
317    pub duration_ms: Option<u64>,
318    /// Whether the command should return immediately without waiting for selection.
319    #[serde(default)]
320    pub non_blocking: bool,
321    /// Whether pane selection should not run a follow-up command.
322    #[serde(default)]
323    pub no_command: bool,
324    /// Optional template command executed after pane selection.
325    #[serde(default)]
326    pub template: Option<String>,
327}
328
329/// Request payload for `pipe-pane`.
330#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
331pub struct PipePaneRequest {
332    /// The exact pane target.
333    pub target: PaneTarget,
334    /// Whether pipe output should be written into the pane (`-I`).
335    #[serde(default)]
336    pub stdin: bool,
337    /// Whether pane output should be written into the pipe (`-O`).
338    #[serde(default)]
339    pub stdout: bool,
340    /// Whether an existing pipe should be toggled off without reopening (`-o`).
341    #[serde(default)]
342    pub once: bool,
343    /// The optional shell command. Omitting it closes any existing pipe.
344    #[serde(default)]
345    pub command: Option<String>,
346}
347
348/// Request payload for `respawn-pane`.
349#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
350pub struct RespawnPaneRequest {
351    /// The exact pane target.
352    pub target: PaneTarget,
353    /// Whether a running pane should be killed before respawning (`-k`).
354    #[serde(default)]
355    pub kill: bool,
356    /// Optional working-directory override.
357    #[serde(default)]
358    pub start_directory: Option<PathBuf>,
359    /// Optional per-spawn environment overrides in `NAME=VALUE` form.
360    #[serde(default)]
361    pub environment: Option<Vec<String>>,
362    /// Legacy optional shell command argv. A single argument is executed via
363    /// `$SHELL -c`.
364    #[serde(default)]
365    pub command: Option<Vec<String>>,
366    /// Explicit process launch mode.
367    #[serde(default)]
368    pub process_command: Option<ProcessCommand>,
369}
370
371impl<'de> Deserialize<'de> for RespawnPaneRequest {
372    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
373    where
374        D: Deserializer<'de>,
375    {
376        deserializer.deserialize_struct(
377            "RespawnPaneRequest",
378            &[
379                "target",
380                "kill",
381                "start_directory",
382                "environment",
383                "command",
384                "process_command",
385            ],
386            compat::RespawnPaneRequestVisitor,
387        )
388    }
389}
390
391/// Request payload for `select-pane`.
392#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
393pub struct SelectPaneRequest {
394    /// The exact pane target.
395    pub target: PaneTarget,
396    /// Optional pane title to set without changing the active pane (`-T`).
397    #[serde(default)]
398    pub title: Option<String>,
399    /// Optional pane input state mutation (`select-pane -d` / `-e`).
400    #[serde(default)]
401    pub input_disabled: Option<bool>,
402    /// Whether an existing zoomed window should remain zoomed after selecting.
403    #[serde(default)]
404    pub preserve_zoom: bool,
405    /// Optional pane style to set on the pane-local `window-style` option (`-P`).
406    #[serde(default)]
407    pub style: Option<String>,
408}
409
410impl<'de> Deserialize<'de> for SelectPaneRequest {
411    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
412    where
413        D: Deserializer<'de>,
414    {
415        deserializer.deserialize_struct(
416            "SelectPaneRequest",
417            &[
418                "target",
419                "title",
420                "input_disabled",
421                "preserve_zoom",
422                "style",
423            ],
424            compat::SelectPaneRequestVisitor,
425        )
426    }
427}
428
429/// SDK pane input request that can address a stable pane id.
430#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
431pub struct PaneInputRequest {
432    /// The exact pane target or stable pane id.
433    pub target: PaneTargetRef,
434    /// Text or key tokens to send.
435    pub keys: Vec<String>,
436    /// Whether tokens should be written literally instead of interpreted as
437    /// tmux-compatible key names.
438    #[serde(default)]
439    pub literal: bool,
440}
441
442/// SDK pane input broadcast request with stable pane-id targeting.
443#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
444pub struct PaneBroadcastInputRequest {
445    /// Pane targets addressed in caller order.
446    pub targets: Vec<PaneTargetRef>,
447    /// Text or key tokens to send to each pane.
448    pub keys: Vec<String>,
449    /// Whether tokens should be written literally instead of interpreted as
450    /// tmux-compatible key names.
451    #[serde(default)]
452    pub literal: bool,
453}
454
455/// SDK resize request that can address a stable pane id.
456#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
457pub struct PaneResizeRequest {
458    /// The exact pane target or stable pane id.
459    pub target: PaneTargetRef,
460    /// The semantic resize request.
461    pub adjustment: ResizePaneAdjustment,
462}
463
464/// SDK kill request that can address a stable pane id.
465#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
466pub struct PaneKillRequest {
467    /// The exact pane target or stable pane id.
468    pub target: PaneTargetRef,
469    /// Whether all panes except the target should be killed.
470    #[serde(default)]
471    pub kill_all_except: bool,
472}
473
474/// SDK respawn request that can address a stable pane id.
475#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
476pub struct PaneRespawnRequest {
477    /// The exact pane target or stable pane id.
478    pub target: PaneTargetRef,
479    /// Whether a running pane should be killed before respawning.
480    #[serde(default)]
481    pub kill: bool,
482    /// Optional working-directory override.
483    #[serde(default)]
484    pub start_directory: Option<PathBuf>,
485    /// Optional per-spawn environment overrides in `NAME=VALUE` form.
486    #[serde(default)]
487    pub environment: Option<Vec<String>>,
488    /// Legacy optional shell command argv. A single argument is executed via
489    /// `$SHELL -c`.
490    #[serde(default)]
491    pub command: Option<Vec<String>>,
492    /// Explicit process launch mode.
493    #[serde(default)]
494    pub process_command: Option<ProcessCommand>,
495    /// Optional pane-local `remain-on-exit` override applied before respawn.
496    #[serde(default)]
497    pub keep_alive_on_exit: Option<bool>,
498}
499
500/// SDK snapshot request that can address a stable pane id.
501#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
502pub struct PaneSnapshotRefRequest {
503    /// The exact pane target or stable pane id.
504    pub target: PaneTargetRef,
505}
506
507/// SDK select/title request that can address a stable pane id.
508#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
509pub struct PaneSelectRequest {
510    /// The exact pane target or stable pane id.
511    pub target: PaneTargetRef,
512    /// Optional pane title to set without changing the active pane.
513    #[serde(default)]
514    pub title: Option<String>,
515}
516
517/// Direction used by `select-pane -U/-D/-L/-R`.
518#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
519pub enum SelectPaneDirection {
520    /// Select the pane above the target pane.
521    Up,
522    /// Select the pane below the target pane.
523    Down,
524    /// Select the pane to the left of the target pane.
525    Left,
526    /// Select the pane to the right of the target pane.
527    Right,
528}
529
530/// Request payload for directional `select-pane`.
531#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
532pub struct SelectPaneAdjacentRequest {
533    /// The pane used as the directional anchor.
534    pub target: PaneTarget,
535    /// The requested adjacent-pane direction.
536    pub direction: SelectPaneDirection,
537    /// Whether an existing zoomed window should remain zoomed after selecting.
538    #[serde(default)]
539    pub preserve_zoom: bool,
540}
541
542impl<'de> Deserialize<'de> for SelectPaneAdjacentRequest {
543    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
544    where
545        D: Deserializer<'de>,
546    {
547        deserializer.deserialize_struct(
548            "SelectPaneAdjacentRequest",
549            &["target", "direction", "preserve_zoom"],
550            compat::SelectPaneAdjacentRequestVisitor,
551        )
552    }
553}
554
555/// Request payload for `select-pane -m` and `select-pane -M`.
556#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
557pub struct SelectPaneMarkRequest {
558    /// The pane target used to resolve the current session/window context.
559    pub target: PaneTarget,
560    /// Whether to clear the existing marked pane instead of toggling the target.
561    pub clear: bool,
562    /// Optional pane title to set while applying the mark operation (`-T`).
563    #[serde(default)]
564    pub title: Option<String>,
565}
566
567/// Request payload for the daemon-backed pane snapshot endpoint.
568///
569/// Unlike [`CapturePaneRequest`](crate::CapturePaneRequest), which returns a
570/// pre-rendered byte stream of the visible viewport, this request asks the
571/// daemon to expose its live in-memory grid as structured cells. The daemon
572/// reads the cells directly from the rmux-core screen that is fed by its
573/// crate-private terminal parser, so there is no `String::from_utf8_lossy`
574/// reconstruction step on either side of the wire.
575#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
576pub struct PaneSnapshotRequest {
577    /// The exact pane target whose visible viewport should be captured.
578    pub target: PaneTarget,
579}
580
581/// Starting position for a pane-output subscription cursor.
582#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
583pub enum PaneOutputSubscriptionStart {
584    /// Start after the newest output currently retained by the pane.
585    Now,
586    /// Start at the oldest retained output event.
587    Oldest,
588}
589
590/// Request payload for subscribing to live pane-output events.
591#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
592pub struct SubscribePaneOutputRequest {
593    /// The exact pane target whose output should be subscribed.
594    pub target: PaneTarget,
595    /// The initial cursor position.
596    pub start: PaneOutputSubscriptionStart,
597}
598
599/// Request payload for subscribing to live pane-output events by slot or id.
600#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
601pub struct SubscribePaneOutputRefRequest {
602    /// The exact pane target or stable pane id whose output should be
603    /// subscribed.
604    pub target: PaneTargetRef,
605    /// The initial cursor position.
606    pub start: PaneOutputSubscriptionStart,
607}
608
609/// Request payload for unsubscribing from live pane-output events.
610#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
611pub struct UnsubscribePaneOutputRequest {
612    /// The subscription to remove.
613    pub subscription_id: PaneOutputSubscriptionId,
614}
615
616/// Request payload for polling a pane-output subscription cursor.
617#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
618pub struct PaneOutputCursorRequest {
619    /// The subscription whose cursor should be polled.
620    pub subscription_id: PaneOutputSubscriptionId,
621    /// Optional caller-requested event cap. The server clamps this to the
622    /// recorded v1 default batch limit.
623    #[serde(default)]
624    pub max_events: Option<u16>,
625}
626
627/// Request payload for `send-keys`.
628#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
629pub struct SendKeysRequest {
630    /// The exact pane target.
631    pub target: PaneTarget,
632    /// Key tokens in left-to-right order.
633    pub keys: Vec<String>,
634}
635
636/// Extended request payload for `send-keys`.
637#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
638pub struct SendKeysExtRequest {
639    /// The optional explicit pane target.
640    pub target: Option<PaneTarget>,
641    /// Key tokens in left-to-right order.
642    pub keys: Vec<String>,
643    /// Whether tmux format expansion should be applied to each token first.
644    pub expand_formats: bool,
645    /// Whether each token should be interpreted as a hexadecimal byte value.
646    pub hex: bool,
647    /// Whether tokens should be sent as literal bytes instead of key names.
648    #[serde(default)]
649    pub literal: bool,
650    /// Whether keys should be dispatched through the client's key table.
651    pub dispatch_key_table: bool,
652    /// Whether tokens describe copy-mode commands.
653    pub copy_mode_command: bool,
654    /// Whether the payload should be treated as a mouse event.
655    pub forward_mouse_event: bool,
656    /// Whether the target terminal should be reset before sending keys.
657    pub reset_terminal: bool,
658    /// Optional tmux repeat count for command or key dispatch.
659    pub repeat_count: Option<usize>,
660}
661
662/// Further-extended request payload for `send-keys -c`.
663///
664/// This is intentionally separate from [`SendKeysExtRequest`] so the original
665/// bincode field order remains wire-compatible with older clients and daemons.
666#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
667pub struct SendKeysExt2Request {
668    /// The optional explicit pane target.
669    pub target: Option<PaneTarget>,
670    /// Key tokens in left-to-right order.
671    pub keys: Vec<String>,
672    /// Whether tmux format expansion should be applied to each token first.
673    pub expand_formats: bool,
674    /// Whether each token should be interpreted as a hexadecimal byte value.
675    pub hex: bool,
676    /// Whether tokens should be sent as literal bytes instead of key names.
677    #[serde(default)]
678    pub literal: bool,
679    /// Whether keys should be dispatched through the client's key table.
680    pub dispatch_key_table: bool,
681    /// Whether tokens describe copy-mode commands.
682    pub copy_mode_command: bool,
683    /// Whether the payload should be treated as a mouse event.
684    pub forward_mouse_event: bool,
685    /// Whether the target terminal should be reset before sending keys.
686    pub reset_terminal: bool,
687    /// Optional tmux repeat count for command or key dispatch.
688    pub repeat_count: Option<usize>,
689    /// Optional target client used for current-pane resolution and client key dispatch.
690    pub target_client: Option<String>,
691}