tmux_rs/
lib.rs

1// Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
2//
3// Permission to use, copy, modify, and distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
12// IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
13// OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14#![expect(rustdoc::broken_intra_doc_links, reason = "github markdown callout")]
15#![doc = include_str!("../README.md")]
16#![allow(
17    non_camel_case_types,
18    clippy::manual_range_contains,
19    clippy::too_many_arguments,
20    reason = "won't fix: match upstream"
21)]
22#![allow(clippy::missing_safety_doc, reason = "currently using too much unsafe")]
23// will fix:
24#![allow(unused)] // TODO 900
25#![allow(unpredictable_function_pointer_comparisons)] // TODO 2
26// extra enabled:
27#![warn(clippy::multiple_crate_versions)]
28#![warn(clippy::shadow_same)]
29#![allow(clippy::shadow_unrelated)] // TODO, 134 instances probably some latent bugs
30#![allow(clippy::shadow_reuse)] // 145 instances
31
32pub(crate) use std::sync::atomic;
33
34mod compat;
35use compat::vis_flags;
36use compat::{strtonum, strtonum_};
37
38mod ncurses_;
39use ncurses_::*;
40
41pub(crate) mod libc;
42pub(crate) use libc::errno;
43pub(crate) use libc::*;
44pub(crate) use libc::{free_, memcpy_, memcpy__, strcaseeq_, streq_};
45
46#[cfg(feature = "sixel")]
47mod image_;
48#[cfg(feature = "sixel")]
49mod image_sixel;
50#[cfg(feature = "sixel")]
51use image_sixel::sixel_image;
52
53#[cfg(feature = "utempter")]
54mod utempter;
55
56use core::{
57    ffi::{
58        CStr, c_int, c_long, c_longlong, c_short, c_uchar, c_uint, c_ulonglong, c_ushort, c_void,
59    },
60    mem::{ManuallyDrop, MaybeUninit, size_of, zeroed},
61    ops::ControlFlow,
62    ptr::{NonNull, null, null_mut},
63};
64use std::sync::atomic::AtomicU32;
65
66// libevent2
67mod event_;
68use event_::*;
69
70use crate::compat::{
71    RB_GENERATE,
72    queue::{
73        Entry, ListEntry, list_entry, list_head, tailq_entry, tailq_first, tailq_foreach,
74        tailq_head, tailq_next,
75    },
76    tree::{GetEntry, rb_entry, rb_head},
77};
78
79unsafe extern "C" {
80    static mut environ: *mut *mut u8;
81    fn strsep(_: *mut *mut u8, _delim: *const u8) -> *mut u8;
82}
83
84#[inline]
85const fn transmute_ptr<T>(value: Option<NonNull<T>>) -> *mut T {
86    match value {
87        Some(ptr) => ptr.as_ptr(),
88        None => null_mut(),
89    }
90}
91
92use compat::imsg::imsg; // TODO move
93
94type wchar_t = core::ffi::c_int;
95#[cfg(target_os = "linux")]
96unsafe extern "C" {
97    static mut stdin: *mut FILE;
98    static mut stdout: *mut FILE;
99    static mut stderr: *mut FILE;
100}
101#[cfg(target_os = "macos")]
102unsafe extern "C" {
103    #[link_name = "__stdinp"]
104    static mut stdin: *mut FILE;
105
106    #[link_name = "__stdoutp"]
107    static mut stdout: *mut FILE;
108
109    #[link_name = "__stderrp"]
110    static mut stderr: *mut FILE;
111}
112
113// use crate::tmux_protocol_h::*;
114
115type bitstr_t = u8;
116
117unsafe fn bit_alloc(nbits: u32) -> *mut u8 {
118    unsafe { libc::calloc(nbits.div_ceil(8) as usize, 1).cast() }
119}
120unsafe fn bit_set(bits: *mut u8, i: u32) {
121    unsafe {
122        let byte_index = i / 8;
123        let bit_index = i % 8;
124        *bits.add(byte_index as usize) |= 1 << bit_index;
125    }
126}
127
128#[inline]
129unsafe fn bit_clear(bits: *mut u8, i: u32) {
130    unsafe {
131        let byte_index = i / 8;
132        let bit_index = i % 8;
133        *bits.add(byte_index as usize) &= !(1 << bit_index);
134    }
135}
136
137/// clear bits start..=stop in bitstring
138unsafe fn bit_nclear(bits: *mut u8, start: u32, stop: u32) {
139    unsafe {
140        // TODO this is written inefficiently, assuming the compiler will optimize it. if it doesn't rewrite it
141        for i in start..=stop {
142            bit_clear(bits, i);
143        }
144    }
145}
146
147unsafe fn bit_test(bits: *const u8, i: u32) -> bool {
148    unsafe {
149        let byte_index = i / 8;
150        let bit_index = i % 8;
151        (*bits.add(byte_index as usize) & (1 << bit_index)) != 0
152    }
153}
154
155const TTY_NAME_MAX: usize = 32;
156
157// discriminant structs
158struct discr_alerts_entry;
159struct discr_all_entry;
160struct discr_by_uri_entry;
161struct discr_by_inner_entry;
162struct discr_data_entry;
163struct discr_entry;
164struct discr_gentry;
165struct discr_index_entry;
166struct discr_name_entry;
167struct discr_pending_entry;
168struct discr_sentry;
169struct discr_time_entry;
170struct discr_tree_entry;
171struct discr_wentry;
172
173// /usr/include/paths.h
174const _PATH_TTY: *const u8 = c!("/dev/tty");
175
176const _PATH_BSHELL: *const u8 = c!("/bin/sh");
177const _PATH_BSHELL_STR: &str = "/bin/sh";
178
179const _PATH_DEFPATH: *const u8 = c!("/usr/bin:/bin");
180const _PATH_DEV: *const u8 = c!("/dev/");
181const _PATH_DEVNULL: *const u8 = c!("/dev/null");
182const _PATH_VI: &str = "/usr/bin/vi";
183
184const SIZEOF_PATH_DEV: usize = 6;
185
186macro_rules! env_or {
187    ($key:literal, $default:expr) => {
188        match std::option_env!($key) {
189            Some(value) => value,
190            None => $default,
191        }
192    };
193}
194
195const TMUX_VERSION: &str = env_or!("TMUX_VERSION", env!("CARGO_PKG_VERSION"));
196const TMUX_CONF: &str = env_or!(
197    "TMUX_CONF",
198    "/etc/tmux.conf:~/.tmux.conf:$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"
199);
200const TMUX_SOCK: &str = env_or!("TMUX_SOCK", "$TMUX_TMPDIR:/tmp/");
201const TMUX_TERM: &str = env_or!("TMUX_TERM", "screen");
202const TMUX_LOCK_CMD: &str = env_or!("TMUX_LOCK_CMD", "lock -np");
203
204/// Minimum layout cell size, NOT including border lines.
205const PANE_MINIMUM: u32 = 1;
206
207/// Automatic name refresh interval, in microseconds. Must be < 1 second.
208const NAME_INTERVAL: libc::suseconds_t = 500000;
209
210/// Default pixel cell sizes.
211const DEFAULT_XPIXEL: u32 = 16;
212const DEFAULT_YPIXEL: u32 = 32;
213
214// Alert option values
215#[repr(i32)]
216#[derive(Copy, Clone, num_enum::TryFromPrimitive)]
217enum alert_option {
218    ALERT_NONE,
219    ALERT_ANY,
220    ALERT_CURRENT,
221    ALERT_OTHER,
222}
223
224// Visual option values
225#[repr(i32)]
226#[derive(Copy, Clone, Eq, PartialEq, num_enum::TryFromPrimitive)]
227enum visual_option {
228    VISUAL_OFF,
229    VISUAL_ON,
230    VISUAL_BOTH,
231}
232
233// No key or unknown key.
234const KEYC_NONE: c_ulonglong = 0x000ff000000000;
235const KEYC_UNKNOWN: c_ulonglong = 0x000fe000000000;
236
237// Base for special (that is, not Unicode) keys. An enum must be at most a
238// signed int, so these are based in the highest Unicode PUA.
239const KEYC_BASE: c_ulonglong = 0x0000000010e000;
240const KEYC_USER: c_ulonglong = 0x0000000010f000;
241const KEYC_USER_END: c_ulonglong = KEYC_USER + KEYC_NUSER;
242
243// Key modifier bits
244const KEYC_META: c_ulonglong = 0x00100000000000;
245const KEYC_CTRL: c_ulonglong = 0x00200000000000;
246const KEYC_SHIFT: c_ulonglong = 0x00400000000000;
247
248// Key flag bits.
249const KEYC_LITERAL: c_ulonglong = 0x01000000000000;
250const KEYC_KEYPAD: c_ulonglong = 0x02000000000000;
251const KEYC_CURSOR: c_ulonglong = 0x04000000000000;
252const KEYC_IMPLIED_META: c_ulonglong = 0x08000000000000;
253const KEYC_BUILD_MODIFIERS: c_ulonglong = 0x10000000000000;
254const KEYC_VI: c_ulonglong = 0x20000000000000;
255const KEYC_SENT: c_ulonglong = 0x40000000000000;
256
257// Masks for key bits.
258const KEYC_MASK_MODIFIERS: c_ulonglong = 0x00f00000000000;
259const KEYC_MASK_FLAGS: c_ulonglong = 0xff000000000000;
260const KEYC_MASK_KEY: c_ulonglong = 0x000fffffffffff;
261
262const KEYC_NUSER: c_ulonglong = 1000;
263
264#[allow(non_snake_case)]
265#[inline(always)]
266fn KEYC_IS_MOUSE(key: key_code) -> bool {
267    const KEYC_MOUSE: c_ulonglong = keyc::KEYC_MOUSE as c_ulonglong;
268    const KEYC_BSPACE: c_ulonglong = keyc::KEYC_BSPACE as c_ulonglong;
269
270    (key & KEYC_MASK_KEY) >= KEYC_MOUSE && (key & KEYC_MASK_KEY) < KEYC_BSPACE
271}
272
273#[allow(non_snake_case)]
274#[inline(always)]
275fn KEYC_IS_UNICODE(key: key_code) -> bool {
276    let masked = key & KEYC_MASK_KEY;
277
278    const KEYC_BASE_END: c_ulonglong = keyc::KEYC_BASE_END as c_ulonglong;
279    masked > 0x7f
280        && (masked < KEYC_BASE || masked >= KEYC_BASE_END)
281        && (masked < KEYC_USER || masked >= KEYC_USER_END)
282}
283
284const KEYC_CLICK_TIMEOUT: i32 = 300;
285
286/// A single key. This can be ASCII or Unicode or one of the keys between
287/// KEYC_BASE and KEYC_BASE_END.
288type key_code = core::ffi::c_ulonglong;
289
290// skipped C0 control characters
291
292/* C0 control characters */
293#[repr(u64)]
294#[derive(Copy, Clone)]
295enum c0 {
296    C0_NUL,
297    C0_SOH,
298    C0_STX,
299    C0_ETX,
300    C0_EOT,
301    C0_ENQ,
302    C0_ASC,
303    C0_BEL,
304    C0_BS,
305    C0_HT,
306    C0_LF,
307    C0_VT,
308    C0_FF,
309    C0_CR,
310    C0_SO,
311    C0_SI,
312    C0_DLE,
313    C0_DC1,
314    C0_DC2,
315    C0_DC3,
316    C0_DC4,
317    C0_NAK,
318    C0_SYN,
319    C0_ETB,
320    C0_CAN,
321    C0_EM,
322    C0_SUB,
323    C0_ESC,
324    C0_FS,
325    C0_GS,
326    C0_RS,
327    C0_US,
328}
329
330// idea write a custom top level macro
331// which allows me to annotate a variant
332// that should be converted to mouse key
333/*
334enum mouse_keys {
335  KEYC_MOUSE,
336
337  #[keyc_mouse_key]
338  MOUSEMOVE,
339}
340*/
341include!("keyc_mouse_key.rs");
342
343/// Termcap codes.
344#[repr(u32)]
345#[derive(Copy, Clone, num_enum::TryFromPrimitive)]
346enum tty_code_code {
347    TTYC_ACSC,
348    TTYC_AM,
349    TTYC_AX,
350    TTYC_BCE,
351    TTYC_BEL,
352    TTYC_BIDI,
353    TTYC_BLINK,
354    TTYC_BOLD,
355    TTYC_CIVIS,
356    TTYC_CLEAR,
357    TTYC_CLMG,
358    TTYC_CMG,
359    TTYC_CNORM,
360    TTYC_COLORS,
361    TTYC_CR,
362    TTYC_CS,
363    TTYC_CSR,
364    TTYC_CUB,
365    TTYC_CUB1,
366    TTYC_CUD,
367    TTYC_CUD1,
368    TTYC_CUF,
369    TTYC_CUF1,
370    TTYC_CUP,
371    TTYC_CUU,
372    TTYC_CUU1,
373    TTYC_CVVIS,
374    TTYC_DCH,
375    TTYC_DCH1,
376    TTYC_DIM,
377    TTYC_DL,
378    TTYC_DL1,
379    TTYC_DSBP,
380    TTYC_DSEKS,
381    TTYC_DSFCS,
382    TTYC_DSMG,
383    TTYC_E3,
384    TTYC_ECH,
385    TTYC_ED,
386    TTYC_EL,
387    TTYC_EL1,
388    TTYC_ENACS,
389    TTYC_ENBP,
390    TTYC_ENEKS,
391    TTYC_ENFCS,
392    TTYC_ENMG,
393    TTYC_FSL,
394    TTYC_HLS,
395    TTYC_HOME,
396    TTYC_HPA,
397    TTYC_ICH,
398    TTYC_ICH1,
399    TTYC_IL,
400    TTYC_IL1,
401    TTYC_INDN,
402    TTYC_INVIS,
403    TTYC_KCBT,
404    TTYC_KCUB1,
405    TTYC_KCUD1,
406    TTYC_KCUF1,
407    TTYC_KCUU1,
408    TTYC_KDC2,
409    TTYC_KDC3,
410    TTYC_KDC4,
411    TTYC_KDC5,
412    TTYC_KDC6,
413    TTYC_KDC7,
414    TTYC_KDCH1,
415    TTYC_KDN2,
416    TTYC_KDN3,
417    TTYC_KDN4,
418    TTYC_KDN5,
419    TTYC_KDN6,
420    TTYC_KDN7,
421    TTYC_KEND,
422    TTYC_KEND2,
423    TTYC_KEND3,
424    TTYC_KEND4,
425    TTYC_KEND5,
426    TTYC_KEND6,
427    TTYC_KEND7,
428    TTYC_KF1,
429    TTYC_KF10,
430    TTYC_KF11,
431    TTYC_KF12,
432    TTYC_KF13,
433    TTYC_KF14,
434    TTYC_KF15,
435    TTYC_KF16,
436    TTYC_KF17,
437    TTYC_KF18,
438    TTYC_KF19,
439    TTYC_KF2,
440    TTYC_KF20,
441    TTYC_KF21,
442    TTYC_KF22,
443    TTYC_KF23,
444    TTYC_KF24,
445    TTYC_KF25,
446    TTYC_KF26,
447    TTYC_KF27,
448    TTYC_KF28,
449    TTYC_KF29,
450    TTYC_KF3,
451    TTYC_KF30,
452    TTYC_KF31,
453    TTYC_KF32,
454    TTYC_KF33,
455    TTYC_KF34,
456    TTYC_KF35,
457    TTYC_KF36,
458    TTYC_KF37,
459    TTYC_KF38,
460    TTYC_KF39,
461    TTYC_KF4,
462    TTYC_KF40,
463    TTYC_KF41,
464    TTYC_KF42,
465    TTYC_KF43,
466    TTYC_KF44,
467    TTYC_KF45,
468    TTYC_KF46,
469    TTYC_KF47,
470    TTYC_KF48,
471    TTYC_KF49,
472    TTYC_KF5,
473    TTYC_KF50,
474    TTYC_KF51,
475    TTYC_KF52,
476    TTYC_KF53,
477    TTYC_KF54,
478    TTYC_KF55,
479    TTYC_KF56,
480    TTYC_KF57,
481    TTYC_KF58,
482    TTYC_KF59,
483    TTYC_KF6,
484    TTYC_KF60,
485    TTYC_KF61,
486    TTYC_KF62,
487    TTYC_KF63,
488    TTYC_KF7,
489    TTYC_KF8,
490    TTYC_KF9,
491    TTYC_KHOM2,
492    TTYC_KHOM3,
493    TTYC_KHOM4,
494    TTYC_KHOM5,
495    TTYC_KHOM6,
496    TTYC_KHOM7,
497    TTYC_KHOME,
498    TTYC_KIC2,
499    TTYC_KIC3,
500    TTYC_KIC4,
501    TTYC_KIC5,
502    TTYC_KIC6,
503    TTYC_KIC7,
504    TTYC_KICH1,
505    TTYC_KIND,
506    TTYC_KLFT2,
507    TTYC_KLFT3,
508    TTYC_KLFT4,
509    TTYC_KLFT5,
510    TTYC_KLFT6,
511    TTYC_KLFT7,
512    TTYC_KMOUS,
513    TTYC_KNP,
514    TTYC_KNXT2,
515    TTYC_KNXT3,
516    TTYC_KNXT4,
517    TTYC_KNXT5,
518    TTYC_KNXT6,
519    TTYC_KNXT7,
520    TTYC_KPP,
521    TTYC_KPRV2,
522    TTYC_KPRV3,
523    TTYC_KPRV4,
524    TTYC_KPRV5,
525    TTYC_KPRV6,
526    TTYC_KPRV7,
527    TTYC_KRI,
528    TTYC_KRIT2,
529    TTYC_KRIT3,
530    TTYC_KRIT4,
531    TTYC_KRIT5,
532    TTYC_KRIT6,
533    TTYC_KRIT7,
534    TTYC_KUP2,
535    TTYC_KUP3,
536    TTYC_KUP4,
537    TTYC_KUP5,
538    TTYC_KUP6,
539    TTYC_KUP7,
540    TTYC_MS,
541    TTYC_NOBR,
542    TTYC_OL,
543    TTYC_OP,
544    TTYC_RECT,
545    TTYC_REV,
546    TTYC_RGB,
547    TTYC_RI,
548    TTYC_RIN,
549    TTYC_RMACS,
550    TTYC_RMCUP,
551    TTYC_RMKX,
552    TTYC_SE,
553    TTYC_SETAB,
554    TTYC_SETAF,
555    TTYC_SETAL,
556    TTYC_SETRGBB,
557    TTYC_SETRGBF,
558    TTYC_SETULC,
559    TTYC_SETULC1,
560    TTYC_SGR0,
561    TTYC_SITM,
562    TTYC_SMACS,
563    TTYC_SMCUP,
564    TTYC_SMKX,
565    TTYC_SMOL,
566    TTYC_SMSO,
567    TTYC_SMUL,
568    TTYC_SMULX,
569    TTYC_SMXX,
570    TTYC_SXL,
571    TTYC_SS,
572    TTYC_SWD,
573    TTYC_SYNC,
574    TTYC_TC,
575    TTYC_TSL,
576    TTYC_U8,
577    TTYC_VPA,
578    TTYC_XT,
579}
580
581const WHITESPACE: *const u8 = c!(" ");
582
583#[repr(i32)]
584#[derive(Copy, Clone, Eq, PartialEq, num_enum::TryFromPrimitive)]
585enum modekey {
586    MODEKEY_EMACS = 0,
587    MODEKEY_VI = 1,
588}
589
590bitflags::bitflags! {
591    /// Grid flags.
592    #[repr(transparent)]
593    #[derive(Copy, Clone, Eq, PartialEq)]
594    struct mode_flag : i32 {
595        const MODE_CURSOR = 0x1;
596        const MODE_INSERT = 0x2;
597        const MODE_KCURSOR = 0x4;
598        const MODE_KKEYPAD = 0x8;
599        const MODE_WRAP = 0x10;
600        const MODE_MOUSE_STANDARD = 0x20;
601        const MODE_MOUSE_BUTTON = 0x40;
602        const MODE_CURSOR_BLINKING = 0x80;
603        const MODE_MOUSE_UTF8 = 0x100;
604        const MODE_MOUSE_SGR = 0x200;
605        const MODE_BRACKETPASTE = 0x400;
606        const MODE_FOCUSON = 0x800;
607        const MODE_MOUSE_ALL = 0x1000;
608        const MODE_ORIGIN = 0x2000;
609        const MODE_CRLF = 0x4000;
610        const MODE_KEYS_EXTENDED = 0x8000;
611        const MODE_CURSOR_VERY_VISIBLE = 0x10000;
612        const MODE_CURSOR_BLINKING_SET = 0x20000;
613        const MODE_KEYS_EXTENDED_2 = 0x40000;
614    }
615}
616
617const ALL_MODES: i32 = 0xffffff;
618const ALL_MOUSE_MODES: mode_flag = mode_flag::MODE_MOUSE_STANDARD
619    .union(mode_flag::MODE_MOUSE_BUTTON)
620    .union(mode_flag::MODE_MOUSE_ALL);
621const MOTION_MOUSE_MODES: mode_flag = mode_flag::MODE_MOUSE_BUTTON.union(mode_flag::MODE_MOUSE_ALL);
622const CURSOR_MODES: mode_flag = mode_flag::MODE_CURSOR
623    .union(mode_flag::MODE_CURSOR_BLINKING)
624    .union(mode_flag::MODE_CURSOR_VERY_VISIBLE);
625const EXTENDED_KEY_MODES: mode_flag =
626    mode_flag::MODE_KEYS_EXTENDED.union(mode_flag::MODE_KEYS_EXTENDED_2);
627
628// Mouse protocol constants.
629const MOUSE_PARAM_MAX: u32 = 0xff;
630const MOUSE_PARAM_UTF8_MAX: u32 = 0x7ff;
631const MOUSE_PARAM_BTN_OFF: u32 = 0x20;
632const MOUSE_PARAM_POS_OFF: u32 = 0x21;
633
634/* A single UTF-8 character. */
635type utf8_char = c_uint;
636
637// An expanded UTF-8 character. UTF8_SIZE must be big enough to hold combining
638// characters as well. It can't be more than 32 bytes without changes to how
639// characters are stored.
640const UTF8_SIZE: usize = 21;
641
642#[repr(C)]
643#[derive(Copy, Clone)]
644struct utf8_data {
645    data: [c_uchar; UTF8_SIZE],
646
647    have: c_uchar,
648    size: c_uchar,
649
650    /// 0xff if invalid
651    width: c_uchar,
652}
653
654impl utf8_data {
655    const fn new<const N: usize>(
656        data: [u8; N],
657        have: c_uchar,
658        size: c_uchar,
659        width: c_uchar,
660    ) -> Self {
661        if N >= UTF8_SIZE {
662            panic!("invalid size");
663        }
664
665        let mut padded_data = [0u8; UTF8_SIZE];
666        let mut i = 0usize;
667        while i < N {
668            padded_data[i] = data[i];
669            i += 1;
670        }
671
672        Self {
673            data: padded_data,
674            have,
675            size,
676            width,
677        }
678    }
679}
680
681#[repr(i32)]
682#[derive(Copy, Clone, Eq, PartialEq)]
683enum utf8_state {
684    UTF8_MORE,
685    UTF8_DONE,
686    UTF8_ERROR,
687}
688
689// Colour flags.
690const COLOUR_FLAG_256: i32 = 0x01000000;
691const COLOUR_FLAG_RGB: i32 = 0x02000000;
692
693/// Special colours.
694#[allow(non_snake_case)]
695#[inline]
696fn COLOUR_DEFAULT(c: i32) -> bool {
697    c == 8 || c == 9
698}
699
700// Replacement palette.
701#[repr(C)]
702#[derive(Copy, Clone)]
703struct colour_palette {
704    fg: i32,
705    bg: i32,
706
707    palette: *mut i32,
708    default_palette: *mut i32,
709}
710
711// Grid attributes. Anything above 0xff is stored in an extended cell.
712bitflags::bitflags! {
713    /// Grid flags.
714    #[repr(transparent)]
715    #[derive(Copy, Clone, Eq, PartialEq)]
716    struct grid_attr : u16 {
717        const GRID_ATTR_BRIGHT = 0x1;
718        const GRID_ATTR_DIM = 0x2;
719        const GRID_ATTR_UNDERSCORE = 0x4;
720        const GRID_ATTR_BLINK = 0x8;
721        const GRID_ATTR_REVERSE = 0x10;
722        const GRID_ATTR_HIDDEN = 0x20;
723        const GRID_ATTR_ITALICS = 0x40;
724        const GRID_ATTR_CHARSET = 0x80; // alternative character set
725        const GRID_ATTR_STRIKETHROUGH = 0x100;
726        const GRID_ATTR_UNDERSCORE_2 = 0x200;
727        const GRID_ATTR_UNDERSCORE_3 = 0x400;
728        const GRID_ATTR_UNDERSCORE_4 = 0x800;
729        const GRID_ATTR_UNDERSCORE_5 = 0x1000;
730        const GRID_ATTR_OVERLINE = 0x2000;
731    }
732}
733
734/// All underscore attributes.
735const GRID_ATTR_ALL_UNDERSCORE: grid_attr = grid_attr::GRID_ATTR_UNDERSCORE
736    .union(grid_attr::GRID_ATTR_UNDERSCORE_2)
737    .union(grid_attr::GRID_ATTR_UNDERSCORE_3)
738    .union(grid_attr::GRID_ATTR_UNDERSCORE_4)
739    .union(grid_attr::GRID_ATTR_UNDERSCORE_5);
740
741bitflags::bitflags! {
742    /// Grid flags.
743    #[repr(transparent)]
744    #[derive(Copy, Clone, Eq, PartialEq)]
745    struct grid_flag : u8 {
746        const FG256 = 0x1;
747        const BG256 = 0x2;
748        const PADDING = 0x4;
749        const EXTENDED = 0x8;
750        const SELECTED = 0x10;
751        const NOPALETTE = 0x20;
752        const CLEARED = 0x40;
753    }
754}
755
756/// Grid line flags.
757bitflags::bitflags! {
758    #[repr(transparent)]
759    #[derive(Copy, Clone, Eq, PartialEq)]
760    struct grid_line_flag: i32 {
761        const WRAPPED      = 1 << 0; // 0x1
762        const EXTENDED     = 1 << 1; // 0x2
763        const DEAD         = 1 << 2; // 0x4
764        const START_PROMPT = 1 << 3; // 0x8
765        const START_OUTPUT = 1 << 4; // 0x10
766    }
767}
768
769/// Grid string flags.
770bitflags::bitflags! {
771    #[repr(transparent)]
772    #[derive(Copy, Clone, Eq, PartialEq)]
773    struct grid_string_flags: i32 {
774        const GRID_STRING_WITH_SEQUENCES = 0x1;
775        const GRID_STRING_ESCAPE_SEQUENCES = 0x2;
776        const GRID_STRING_TRIM_SPACES = 0x4;
777        const GRID_STRING_USED_ONLY = 0x8;
778        const GRID_STRING_EMPTY_CELLS = 0x10;
779    }
780}
781
782/// Cell positions.
783#[repr(i32)]
784#[derive(Copy, Clone, Eq, PartialEq)]
785enum cell_type {
786    CELL_INSIDE = 0,
787    CELL_TOPBOTTOM = 1,
788    CELL_LEFTRIGHT = 2,
789    CELL_TOPLEFT = 3,
790    CELL_TOPRIGHT = 4,
791    CELL_BOTTOMLEFT = 5,
792    CELL_BOTTOMRIGHT = 6,
793    CELL_TOPJOIN = 7,
794    CELL_BOTTOMJOIN = 8,
795    CELL_LEFTJOIN = 9,
796    CELL_RIGHTJOIN = 10,
797    CELL_JOIN = 11,
798    CELL_OUTSIDE = 12,
799}
800use cell_type::*; // TODO remove
801
802// Cell borders.
803const CELL_BORDERS: [u8; 13] = [
804    b' ', b'x', b'q', b'l', b'k', b'm', b'j', b'w', b'v', b't', b'u', b'n', b'~',
805];
806const SIMPLE_BORDERS: [u8; 13] = [
807    b' ', b'|', b'-', b'+', b'+', b'+', b'+', b'+', b'+', b'+', b'+', b'+', b'.',
808];
809const PADDED_BORDERS: [u8; 13] = [b' '; 13];
810
811/// Grid cell data.
812#[repr(C)]
813#[derive(Copy, Clone)]
814struct grid_cell {
815    data: utf8_data,
816    attr: grid_attr,
817    flags: grid_flag,
818    fg: i32,
819    bg: i32,
820    us: i32,
821    link: u32,
822}
823
824impl grid_cell {
825    const fn new(
826        data: utf8_data,
827        attr: grid_attr,
828        flags: grid_flag,
829        fg: i32,
830        bg: i32,
831        us: i32,
832        link: u32,
833    ) -> Self {
834        Self {
835            data,
836            attr,
837            flags,
838            fg,
839            bg,
840            us,
841            link,
842        }
843    }
844}
845
846/// Grid extended cell entry.
847#[repr(C)]
848struct grid_extd_entry {
849    data: utf8_char,
850    attr: u16,
851    flags: u8,
852    fg: i32,
853    bg: i32,
854    us: i32,
855    link: u32,
856}
857
858#[derive(Copy, Clone)]
859#[repr(C, align(4))]
860struct grid_cell_entry_data {
861    attr: c_uchar,
862    fg: c_uchar,
863    bg: c_uchar,
864    data: c_uchar,
865}
866
867#[repr(C)]
868union grid_cell_entry_union {
869    offset: u32,
870    data: grid_cell_entry_data,
871}
872
873#[repr(C)]
874struct grid_cell_entry {
875    union_: grid_cell_entry_union,
876    flags: grid_flag,
877}
878
879/// Grid line.
880#[repr(C)]
881struct grid_line {
882    celldata: *mut grid_cell_entry,
883    cellused: u32,
884    cellsize: u32,
885
886    extddata: *mut grid_extd_entry,
887    extdsize: u32,
888
889    flags: grid_line_flag,
890    time: time_t,
891}
892
893const GRID_HISTORY: i32 = 0x1; // scroll lines into history
894
895/// Entire grid of cells.
896#[repr(C)]
897struct grid {
898    flags: i32,
899
900    sx: u32,
901    sy: u32,
902
903    hscrolled: u32,
904    hsize: u32,
905    hlimit: u32,
906
907    linedata: *mut grid_line,
908}
909
910/// Virtual cursor in a grid.
911#[repr(C)]
912struct grid_reader {
913    gd: *mut grid,
914    cx: u32,
915    cy: u32,
916}
917
918/// Style alignment.
919#[repr(i32)]
920#[derive(Copy, Clone, Eq, PartialEq)]
921enum style_align {
922    STYLE_ALIGN_DEFAULT,
923    STYLE_ALIGN_LEFT,
924    STYLE_ALIGN_CENTRE,
925    STYLE_ALIGN_RIGHT,
926    STYLE_ALIGN_ABSOLUTE_CENTRE,
927}
928
929/// Style list.
930#[repr(i32)]
931#[derive(Copy, Clone, Eq, PartialEq)]
932enum style_list {
933    STYLE_LIST_OFF,
934    STYLE_LIST_ON,
935    STYLE_LIST_FOCUS,
936    STYLE_LIST_LEFT_MARKER,
937    STYLE_LIST_RIGHT_MARKER,
938}
939
940/// Style range.
941#[repr(i32)]
942#[derive(Copy, Clone, Eq, PartialEq)]
943enum style_range_type {
944    STYLE_RANGE_NONE,
945    STYLE_RANGE_LEFT,
946    STYLE_RANGE_RIGHT,
947    STYLE_RANGE_PANE,
948    STYLE_RANGE_WINDOW,
949    STYLE_RANGE_SESSION,
950    STYLE_RANGE_USER,
951}
952
953crate::compat::impl_tailq_entry!(style_range, entry, tailq_entry<style_range>);
954// #[derive(crate::compat::TailQEntry)]
955#[repr(C)]
956struct style_range {
957    type_: style_range_type,
958    argument: u32,
959    string: [u8; 16],
960    start: u32,
961    /// not included
962    end: u32,
963
964    // #[entry]
965    entry: tailq_entry<style_range>,
966}
967type style_ranges = tailq_head<style_range>;
968
969/// Style default.
970#[repr(i32)]
971#[derive(Copy, Clone, Eq, PartialEq)]
972enum style_default_type {
973    STYLE_DEFAULT_BASE,
974    STYLE_DEFAULT_PUSH,
975    STYLE_DEFAULT_POP,
976}
977
978/// Style option.
979#[repr(C)]
980#[derive(Copy, Clone)]
981struct style {
982    gc: grid_cell,
983    ignore: i32,
984
985    fill: i32,
986    align: style_align,
987    list: style_list,
988
989    range_type: style_range_type,
990    range_argument: u32,
991    range_string: [u8; 16],
992
993    default_type: style_default_type,
994}
995
996#[cfg(feature = "sixel")]
997crate::compat::impl_tailq_entry!(image, all_entry, tailq_entry<image>);
998#[cfg(feature = "sixel")]
999crate::compat::impl_tailq_entry!(image, entry, tailq_entry<image>);
1000#[cfg(feature = "sixel")]
1001#[repr(C)]
1002#[derive(Copy, Clone)]
1003struct image {
1004    s: *mut screen,
1005    data: *mut sixel_image,
1006    fallback: *mut u8,
1007    px: u32,
1008    py: u32,
1009    sx: u32,
1010    sy: u32,
1011
1012    all_entry: tailq_entry<image>,
1013    entry: tailq_entry<image>,
1014}
1015
1016#[cfg(feature = "sixel")]
1017type images = tailq_head<image>;
1018
1019/// Cursor style.
1020#[repr(i32)]
1021#[derive(Copy, Clone, Eq, PartialEq)]
1022enum screen_cursor_style {
1023    SCREEN_CURSOR_DEFAULT,
1024    SCREEN_CURSOR_BLOCK,
1025    SCREEN_CURSOR_UNDERLINE,
1026    SCREEN_CURSOR_BAR,
1027}
1028
1029/// Virtual screen.
1030#[repr(C)]
1031#[derive(Clone)]
1032struct screen {
1033    title: *mut u8,
1034    path: *mut u8,
1035    titles: *mut screen_titles,
1036
1037    /// grid data
1038    grid: *mut grid,
1039
1040    /// cursor x
1041    cx: u32,
1042    /// cursor y
1043    cy: u32,
1044
1045    /// cursor style
1046    cstyle: screen_cursor_style,
1047    default_cstyle: screen_cursor_style,
1048    /// cursor colour
1049    ccolour: i32,
1050    /// default cursor colour
1051    default_ccolour: i32,
1052
1053    /// scroll region top
1054    rupper: u32,
1055    /// scroll region bottom
1056    rlower: u32,
1057
1058    mode: mode_flag,
1059    default_mode: mode_flag,
1060
1061    saved_cx: u32,
1062    saved_cy: u32,
1063    saved_grid: *mut grid,
1064    saved_cell: grid_cell,
1065    saved_flags: i32,
1066
1067    tabs: *mut bitstr_t,
1068    sel: *mut screen_sel,
1069
1070    #[cfg(feature = "sixel")]
1071    images: images,
1072
1073    write_list: *mut screen_write_cline,
1074
1075    hyperlinks: *mut hyperlinks,
1076}
1077
1078const SCREEN_WRITE_SYNC: i32 = 0x1;
1079
1080// Screen write context.
1081type screen_write_init_ctx_cb = Option<unsafe fn(*mut screen_write_ctx, *mut tty_ctx)>;
1082#[repr(C)]
1083struct screen_write_ctx {
1084    wp: *mut window_pane,
1085    s: *mut screen,
1086
1087    flags: i32,
1088
1089    init_ctx_cb: screen_write_init_ctx_cb,
1090
1091    arg: *mut c_void,
1092
1093    item: *mut screen_write_citem,
1094    scrolled: u32,
1095    bg: u32,
1096}
1097
1098/// Box border lines option.
1099#[repr(i32)]
1100#[derive(Copy, Clone, Default, Eq, PartialEq, num_enum::TryFromPrimitive)]
1101enum box_lines {
1102    #[default]
1103    BOX_LINES_DEFAULT = -1,
1104    BOX_LINES_SINGLE,
1105    BOX_LINES_DOUBLE,
1106    BOX_LINES_HEAVY,
1107    BOX_LINES_SIMPLE,
1108    BOX_LINES_ROUNDED,
1109    BOX_LINES_PADDED,
1110    BOX_LINES_NONE,
1111}
1112
1113/// Pane border lines option.
1114#[repr(i32)]
1115#[derive(Copy, Clone, Default, Eq, PartialEq, num_enum::TryFromPrimitive)]
1116enum pane_lines {
1117    #[default]
1118    PANE_LINES_SINGLE,
1119    PANE_LINES_DOUBLE,
1120    PANE_LINES_HEAVY,
1121    PANE_LINES_SIMPLE,
1122    PANE_LINES_NUMBER,
1123}
1124
1125macro_rules! define_error_unit {
1126    ($error_type:ident) => {
1127        #[derive(Debug)]
1128        struct $error_type;
1129        impl ::std::error::Error for $error_type {}
1130        impl ::std::fmt::Display for $error_type {
1131            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1132                write!(f, "{self:?}")
1133            }
1134        }
1135    };
1136}
1137
1138#[repr(i32)]
1139#[derive(Copy, Clone, num_enum::TryFromPrimitive)]
1140enum pane_border_indicator {
1141    PANE_BORDER_OFF,
1142    PANE_BORDER_COLOUR,
1143    PANE_BORDER_ARROWS,
1144    PANE_BORDER_BOTH,
1145}
1146
1147// Mode returned by window_pane_mode function.
1148const WINDOW_PANE_NO_MODE: i32 = 0;
1149const WINDOW_PANE_COPY_MODE: i32 = 1;
1150const WINDOW_PANE_VIEW_MODE: i32 = 2;
1151
1152// Screen redraw context.
1153#[repr(C)]
1154struct screen_redraw_ctx {
1155    c: *mut client,
1156
1157    statuslines: u32,
1158    statustop: i32,
1159
1160    pane_status: pane_status,
1161    pane_lines: pane_lines,
1162
1163    no_pane_gc: grid_cell,
1164    no_pane_gc_set: i32,
1165
1166    sx: u32,
1167    sy: u32,
1168    ox: u32,
1169    oy: u32,
1170}
1171
1172unsafe fn screen_size_x(s: *const screen) -> u32 {
1173    unsafe { (*(*s).grid).sx }
1174}
1175unsafe fn screen_size_y(s: *const screen) -> u32 {
1176    unsafe { (*(*s).grid).sy }
1177}
1178unsafe fn screen_hsize(s: *const screen) -> u32 {
1179    unsafe { (*(*s).grid).hsize }
1180}
1181unsafe fn screen_hlimit(s: *const screen) -> u32 {
1182    unsafe { (*(*s).grid).hlimit }
1183}
1184
1185// Menu.
1186#[repr(C)]
1187struct menu_item {
1188    name: SyncCharPtr,
1189    key: key_code,
1190    command: SyncCharPtr,
1191}
1192impl menu_item {
1193    const fn new(name: &'static CStr, key: key_code, command: *const u8) -> Self {
1194        Self {
1195            name: SyncCharPtr::new(name),
1196            key,
1197            command: SyncCharPtr(command),
1198        }
1199    }
1200}
1201
1202#[repr(C)]
1203struct menu {
1204    title: *const u8,
1205    items: *mut menu_item,
1206    count: u32,
1207    width: u32,
1208}
1209type menu_choice_cb = Option<unsafe fn(*mut menu, u32, key_code, *mut c_void)>;
1210
1211#[expect(clippy::type_complexity)]
1212/// Window mode. Windows can be in several modes and this is used to call the
1213/// right function to handle input and output.
1214#[repr(C)]
1215struct window_mode {
1216    name: SyncCharPtr,
1217    default_format: SyncCharPtr,
1218
1219    init: unsafe fn(NonNull<window_mode_entry>, *mut cmd_find_state, *mut args) -> *mut screen,
1220    free: unsafe fn(NonNull<window_mode_entry>),
1221    resize: unsafe fn(NonNull<window_mode_entry>, u32, u32),
1222    update: Option<unsafe fn(NonNull<window_mode_entry>)>,
1223    key: Option<
1224        unsafe fn(
1225            NonNull<window_mode_entry>,
1226            *mut client,
1227            *mut session,
1228            *mut winlink,
1229            key_code,
1230            *mut mouse_event,
1231        ),
1232    >,
1233
1234    key_table: Option<unsafe fn(*mut window_mode_entry) -> *const u8>,
1235    command: Option<
1236        unsafe fn(
1237            NonNull<window_mode_entry>,
1238            *mut client,
1239            *mut session,
1240            *mut winlink,
1241            *mut args,
1242            *mut mouse_event,
1243        ),
1244    >,
1245    formats: Option<unsafe fn(*mut window_mode_entry, *mut format_tree)>,
1246}
1247
1248// Active window mode.
1249crate::compat::impl_tailq_entry!(window_mode_entry, entry, tailq_entry<window_mode_entry>);
1250#[repr(C)]
1251struct window_mode_entry {
1252    wp: *mut window_pane,
1253    swp: *mut window_pane,
1254
1255    mode: *const window_mode,
1256    data: *mut c_void,
1257
1258    screen: *mut screen,
1259    prefix: u32,
1260
1261    // #[entry]
1262    entry: tailq_entry<window_mode_entry>,
1263}
1264
1265/// Offsets into pane buffer.
1266#[repr(C)]
1267#[derive(Copy, Clone)]
1268struct window_pane_offset {
1269    used: usize,
1270}
1271
1272/// Queued pane resize.
1273crate::compat::impl_tailq_entry!(window_pane_resize, entry, tailq_entry<window_pane_resize>);
1274#[repr(C)]
1275struct window_pane_resize {
1276    sx: u32,
1277    sy: u32,
1278
1279    osx: u32,
1280    osy: u32,
1281
1282    entry: tailq_entry<window_pane_resize>,
1283}
1284type window_pane_resizes = tailq_head<window_pane_resize>;
1285
1286bitflags::bitflags! {
1287    #[repr(transparent)]
1288    #[derive(Copy, Clone, Eq, PartialEq)]
1289    struct window_pane_flags : i32 {
1290        const PANE_REDRAW = 0x1;
1291        const PANE_DROP = 0x2;
1292        const PANE_FOCUSED = 0x4;
1293        const PANE_VISITED = 0x8;
1294        /* 0x10 unused */
1295        /* 0x20 unused */
1296        const PANE_INPUTOFF = 0x40;
1297        const PANE_CHANGED = 0x80;
1298        const PANE_EXITED = 0x100;
1299        const PANE_STATUSREADY = 0x200;
1300        const PANE_STATUSDRAWN = 0x400;
1301        const PANE_EMPTY = 0x800;
1302        const PANE_STYLECHANGED = 0x1000;
1303        const PANE_UNSEENCHANGES = 0x2000;
1304    }
1305}
1306
1307/// Child window structure.
1308#[repr(C)]
1309struct window_pane {
1310    id: u32,
1311    active_point: u32,
1312
1313    window: *mut window,
1314    options: *mut options,
1315
1316    layout_cell: *mut layout_cell,
1317    saved_layout_cell: *mut layout_cell,
1318
1319    sx: u32,
1320    sy: u32,
1321
1322    xoff: u32,
1323    yoff: u32,
1324
1325    flags: window_pane_flags,
1326
1327    argc: i32,
1328    argv: *mut *mut u8,
1329    shell: *mut u8,
1330    cwd: *mut u8,
1331
1332    pid: pid_t,
1333    tty: [u8; TTY_NAME_MAX],
1334    status: i32,
1335    dead_time: timeval,
1336
1337    fd: i32,
1338    event: *mut bufferevent,
1339
1340    offset: window_pane_offset,
1341    base_offset: usize,
1342
1343    resize_queue: window_pane_resizes,
1344    resize_timer: event,
1345
1346    ictx: *mut input_ctx,
1347
1348    cached_gc: grid_cell,
1349    cached_active_gc: grid_cell,
1350    palette: colour_palette,
1351
1352    pipe_fd: i32,
1353    pipe_event: *mut bufferevent,
1354    pipe_offset: window_pane_offset,
1355
1356    screen: *mut screen,
1357    base: screen,
1358
1359    status_screen: screen,
1360    status_size: usize,
1361
1362    modes: tailq_head<window_mode_entry>,
1363
1364    searchstr: *mut u8,
1365    searchregex: i32,
1366
1367    border_gc_set: i32,
1368    border_gc: grid_cell,
1369
1370    control_bg: i32,
1371    control_fg: i32,
1372
1373    /// link in list of all panes
1374    entry: tailq_entry<window_pane>,
1375    /// link in list of last visited
1376    sentry: tailq_entry<window_pane>,
1377    tree_entry: rb_entry<window_pane>,
1378}
1379type window_panes = tailq_head<window_pane>;
1380type window_pane_tree = rb_head<window_pane>;
1381
1382impl Entry<window_pane, discr_entry> for window_pane {
1383    unsafe fn entry(this: *mut Self) -> *mut tailq_entry<window_pane> {
1384        unsafe { &raw mut (*this).entry }
1385    }
1386}
1387impl Entry<window_pane, discr_sentry> for window_pane {
1388    unsafe fn entry(this: *mut Self) -> *mut tailq_entry<window_pane> {
1389        unsafe { &raw mut (*this).sentry }
1390    }
1391}
1392
1393bitflags::bitflags! {
1394    #[repr(transparent)]
1395    #[derive(Copy, Clone, Eq, PartialEq)]
1396    struct window_flag: i32 {
1397        const BELL = 0x1;
1398        const ACTIVITY = 0x2;
1399        const SILENCE = 0x4;
1400        const ZOOMED = 0x8;
1401        const WASZOOMED = 0x10;
1402        const RESIZE = 0x20;
1403    }
1404}
1405const WINDOW_ALERTFLAGS: window_flag = window_flag::BELL
1406    .union(window_flag::ACTIVITY)
1407    .union(window_flag::SILENCE);
1408
1409/// Window structure.
1410#[repr(C)]
1411struct window {
1412    id: u32,
1413    latest: *mut c_void,
1414
1415    name: *mut u8,
1416    name_event: event,
1417    name_time: timeval,
1418
1419    alerts_timer: event,
1420    offset_timer: event,
1421
1422    activity_time: timeval,
1423
1424    active: *mut window_pane,
1425    last_panes: window_panes,
1426    panes: window_panes,
1427
1428    lastlayout: i32,
1429    layout_root: *mut layout_cell,
1430    saved_layout_root: *mut layout_cell,
1431    old_layout: *mut u8,
1432
1433    sx: u32,
1434    sy: u32,
1435    manual_sx: u32,
1436    manual_sy: u32,
1437    xpixel: u32,
1438    ypixel: u32,
1439
1440    new_sx: u32,
1441    new_sy: u32,
1442    new_xpixel: u32,
1443    new_ypixel: u32,
1444
1445    fill_character: *mut utf8_data,
1446    flags: window_flag,
1447
1448    alerts_queued: i32,
1449    alerts_entry: tailq_entry<window>,
1450
1451    options: *mut options,
1452
1453    references: u32,
1454    winlinks: tailq_head<winlink>,
1455    entry: rb_entry<window>,
1456}
1457type windows = rb_head<window>;
1458// crate::compat::impl_rb_tree_protos!(windows, window);
1459
1460impl crate::compat::queue::Entry<window, discr_alerts_entry> for window {
1461    unsafe fn entry(this: *mut Self) -> *mut tailq_entry<window> {
1462        unsafe { &raw mut (*this).alerts_entry }
1463    }
1464}
1465
1466bitflags::bitflags! {
1467    #[repr(transparent)]
1468    #[derive(Copy, Clone, Eq, PartialEq)]
1469    struct winlink_flags: i32 {
1470        const WINLINK_BELL = 0x1;
1471        const WINLINK_ACTIVITY = 0x2;
1472        const WINLINK_SILENCE = 0x4;
1473        const WINLINK_VISITED = 0x8;
1474    }
1475}
1476const WINLINK_ALERTFLAGS: winlink_flags = winlink_flags::WINLINK_BELL
1477    .union(winlink_flags::WINLINK_ACTIVITY)
1478    .union(winlink_flags::WINLINK_SILENCE);
1479
1480#[repr(C)]
1481#[derive(Copy, Clone)]
1482struct winlink {
1483    idx: i32,
1484    session: *mut session,
1485    window: *mut window,
1486
1487    flags: winlink_flags,
1488
1489    entry: rb_entry<winlink>,
1490
1491    wentry: tailq_entry<winlink>,
1492    sentry: tailq_entry<winlink>,
1493}
1494
1495impl crate::compat::queue::Entry<winlink, discr_wentry> for winlink {
1496    unsafe fn entry(this: *mut Self) -> *mut tailq_entry<winlink> {
1497        unsafe { &raw mut (*this).wentry }
1498    }
1499}
1500
1501impl crate::compat::queue::Entry<winlink, discr_sentry> for winlink {
1502    unsafe fn entry(this: *mut Self) -> *mut tailq_entry<winlink> {
1503        unsafe { &raw mut (*this).sentry }
1504    }
1505}
1506
1507type winlinks = rb_head<winlink>;
1508// crate::compat::impl_rb_tree_protos!(winlinks, winlink);
1509type winlink_stack = tailq_head<winlink>;
1510// crate::compat::impl_rb_tree_protos!(winlink_stack, winlink);
1511
1512/// Window size option.
1513#[repr(i32)]
1514#[derive(Copy, Clone, Eq, PartialEq, num_enum::TryFromPrimitive)]
1515enum window_size_option {
1516    WINDOW_SIZE_LARGEST,
1517    WINDOW_SIZE_SMALLEST,
1518    WINDOW_SIZE_MANUAL,
1519    WINDOW_SIZE_LATEST,
1520}
1521
1522/// Pane border status option.
1523#[repr(i32)]
1524#[derive(Copy, Clone, Eq, PartialEq, num_enum::TryFromPrimitive)]
1525enum pane_status {
1526    PANE_STATUS_OFF,
1527    PANE_STATUS_TOP,
1528    PANE_STATUS_BOTTOM,
1529}
1530
1531/// Layout direction.
1532#[repr(i32)]
1533#[derive(Copy, Clone, Eq, PartialEq)]
1534enum layout_type {
1535    LAYOUT_LEFTRIGHT,
1536    LAYOUT_TOPBOTTOM,
1537    LAYOUT_WINDOWPANE,
1538}
1539
1540/// Layout cells queue.
1541type layout_cells = tailq_head<layout_cell>;
1542
1543/// Layout cell.
1544crate::compat::impl_tailq_entry!(layout_cell, entry, tailq_entry<layout_cell>);
1545#[repr(C)]
1546struct layout_cell {
1547    type_: layout_type,
1548
1549    parent: *mut layout_cell,
1550
1551    sx: u32,
1552    sy: u32,
1553
1554    xoff: u32,
1555    yoff: u32,
1556
1557    wp: *mut window_pane,
1558    cells: layout_cells,
1559
1560    entry: tailq_entry<layout_cell>,
1561}
1562
1563const ENVIRON_HIDDEN: i32 = 0x1;
1564
1565/// Environment variable.
1566#[repr(C)]
1567struct environ_entry {
1568    name: Option<NonNull<u8>>,
1569    value: Option<NonNull<u8>>,
1570
1571    flags: i32,
1572    entry: rb_entry<environ_entry>,
1573}
1574
1575/// Client session.
1576#[repr(C)]
1577struct session_group {
1578    name: *const u8,
1579    sessions: tailq_head<session>,
1580
1581    entry: rb_entry<session_group>,
1582}
1583type session_groups = rb_head<session_group>;
1584
1585const SESSION_PASTING: i32 = 0x1;
1586const SESSION_ALERTED: i32 = 0x2;
1587
1588#[repr(C)]
1589struct session {
1590    id: u32,
1591    name: *mut u8,
1592    cwd: *mut u8,
1593
1594    creation_time: timeval,
1595    last_attached_time: timeval,
1596    activity_time: timeval,
1597    last_activity_time: timeval,
1598
1599    lock_timer: event,
1600
1601    curw: *mut winlink,
1602    lastw: winlink_stack,
1603    windows: winlinks,
1604
1605    statusat: i32,
1606    statuslines: u32,
1607
1608    options: *mut options,
1609
1610    flags: i32,
1611
1612    attached: u32,
1613
1614    tio: *mut termios,
1615
1616    environ: *mut environ,
1617
1618    references: i32,
1619
1620    gentry: tailq_entry<session>,
1621    entry: rb_entry<session>,
1622}
1623type sessions = rb_head<session>;
1624crate::compat::impl_tailq_entry!(session, gentry, tailq_entry<session>);
1625
1626const MOUSE_MASK_BUTTONS: u32 = 195;
1627const MOUSE_MASK_SHIFT: u32 = 4;
1628const MOUSE_MASK_META: u32 = 8;
1629const MOUSE_MASK_CTRL: u32 = 16;
1630const MOUSE_MASK_DRAG: u32 = 32;
1631const MOUSE_MASK_MODIFIERS: u32 = MOUSE_MASK_SHIFT | MOUSE_MASK_META | MOUSE_MASK_CTRL;
1632
1633/* Mouse wheel type. */
1634const MOUSE_WHEEL_UP: u32 = 64;
1635const MOUSE_WHEEL_DOWN: u32 = 65;
1636
1637/* Mouse button type. */
1638const MOUSE_BUTTON_1: u32 = 0;
1639const MOUSE_BUTTON_2: u32 = 1;
1640const MOUSE_BUTTON_3: u32 = 2;
1641const MOUSE_BUTTON_6: u32 = 66;
1642const MOUSE_BUTTON_7: u32 = 67;
1643const MOUSE_BUTTON_8: u32 = 128;
1644const MOUSE_BUTTON_9: u32 = 129;
1645const MOUSE_BUTTON_10: u32 = 130;
1646const MOUSE_BUTTON_11: u32 = 131;
1647
1648// Mouse helpers.
1649#[allow(non_snake_case)]
1650#[inline]
1651fn MOUSE_BUTTONS(b: u32) -> u32 {
1652    b & MOUSE_MASK_BUTTONS
1653}
1654#[allow(non_snake_case)]
1655#[inline]
1656fn MOUSE_WHEEL(b: u32) -> bool {
1657    ((b) & MOUSE_MASK_BUTTONS) == MOUSE_WHEEL_UP || ((b) & MOUSE_MASK_BUTTONS) == MOUSE_WHEEL_DOWN
1658}
1659#[allow(non_snake_case)]
1660#[inline]
1661fn MOUSE_DRAG(b: u32) -> bool {
1662    b & MOUSE_MASK_DRAG != 0
1663}
1664#[allow(non_snake_case)]
1665#[inline]
1666fn MOUSE_RELEASE(b: u32) -> bool {
1667    b & MOUSE_MASK_BUTTONS == 3
1668}
1669
1670/// Mouse input.
1671#[repr(C)]
1672#[derive(Copy, Clone)]
1673struct mouse_event {
1674    valid: i32,
1675    ignore: i32,
1676
1677    key: key_code,
1678
1679    statusat: i32,
1680    statuslines: u32,
1681
1682    x: u32,
1683    y: u32,
1684    b: u32,
1685
1686    lx: u32,
1687    ly: u32,
1688    lb: u32,
1689
1690    ox: u32,
1691    oy: u32,
1692
1693    s: i32,
1694    w: i32,
1695    wp: i32,
1696
1697    sgr_type: u32,
1698    sgr_b: u32,
1699}
1700
1701/// Key event.
1702#[repr(C)]
1703struct key_event {
1704    key: key_code,
1705    m: mouse_event,
1706}
1707
1708bitflags::bitflags! {
1709    #[repr(transparent)]
1710    #[derive(Copy, Clone)]
1711    struct term_flags: i32 {
1712        const TERM_256COLOURS = 0x1;
1713        const TERM_NOAM = 0x2;
1714        const TERM_DECSLRM = 0x4;
1715        const TERM_DECFRA = 0x8;
1716        const TERM_RGBCOLOURS = 0x10;
1717        const TERM_VT100LIKE = 0x20;
1718        const TERM_SIXEL = 0x40;
1719    }
1720}
1721
1722/// Terminal definition.
1723#[repr(C)]
1724struct tty_term {
1725    name: *mut u8,
1726    tty: *mut tty,
1727    features: i32,
1728
1729    acs: [[u8; 2]; c_uchar::MAX as usize + 1],
1730
1731    codes: *mut tty_code,
1732
1733    flags: term_flags,
1734
1735    entry: list_entry<tty_term>,
1736}
1737type tty_terms = list_head<tty_term>;
1738impl ListEntry<tty_term, discr_entry> for tty_term {
1739    unsafe fn field(this: *mut Self) -> *mut list_entry<tty_term> {
1740        unsafe { &raw mut (*this).entry }
1741    }
1742}
1743
1744bitflags::bitflags! {
1745    #[repr(transparent)]
1746    #[derive(Copy, Clone)]
1747    struct tty_flags: i32 {
1748        const TTY_NOCURSOR = 0x1;
1749        const TTY_FREEZE = 0x2;
1750        const TTY_TIMER = 0x4;
1751        const TTY_NOBLOCK = 0x8;
1752        const TTY_STARTED = 0x10;
1753        const TTY_OPENED = 0x20;
1754        const TTY_OSC52QUERY = 0x40;
1755        const TTY_BLOCK = 0x80;
1756        const TTY_HAVEDA = 0x100; // Primary DA.
1757        const TTY_HAVEXDA = 0x200;
1758        const TTY_SYNCING = 0x400;
1759        const TTY_HAVEDA2 = 0x800; // Secondary DA.
1760    }
1761}
1762const TTY_ALL_REQUEST_FLAGS: tty_flags = tty_flags::TTY_HAVEDA
1763    .union(tty_flags::TTY_HAVEDA2)
1764    .union(tty_flags::TTY_HAVEXDA);
1765
1766/// Client terminal.
1767#[repr(C)]
1768struct tty {
1769    client: *mut client,
1770    start_timer: event,
1771    clipboard_timer: event,
1772    last_requests: time_t,
1773
1774    sx: u32,
1775    sy: u32,
1776
1777    xpixel: u32,
1778    ypixel: u32,
1779
1780    cx: u32,
1781    cy: u32,
1782    cstyle: screen_cursor_style,
1783    ccolour: i32,
1784
1785    oflag: i32,
1786    oox: u32,
1787    ooy: u32,
1788    osx: u32,
1789    osy: u32,
1790
1791    mode: mode_flag,
1792    fg: i32,
1793    bg: i32,
1794
1795    rlower: u32,
1796    rupper: u32,
1797
1798    rleft: u32,
1799    rright: u32,
1800
1801    event_in: event,
1802    in_: *mut evbuffer,
1803    event_out: event,
1804    out: *mut evbuffer,
1805    timer: event,
1806    discarded: usize,
1807
1808    tio: termios,
1809
1810    cell: grid_cell,
1811    last_cell: grid_cell,
1812
1813    flags: tty_flags,
1814
1815    term: *mut tty_term,
1816
1817    mouse_last_x: u32,
1818    mouse_last_y: u32,
1819    mouse_last_b: u32,
1820    mouse_drag_flag: i32,
1821    mouse_drag_update: Option<unsafe fn(*mut client, *mut mouse_event)>,
1822    mouse_drag_release: Option<unsafe fn(*mut client, *mut mouse_event)>,
1823
1824    key_timer: event,
1825    key_tree: *mut tty_key,
1826}
1827
1828type tty_ctx_redraw_cb = Option<unsafe fn(*const tty_ctx)>;
1829type tty_ctx_set_client_cb = Option<unsafe fn(*mut tty_ctx, *mut client) -> i32>;
1830
1831#[repr(C)]
1832struct tty_ctx {
1833    s: *mut screen,
1834
1835    redraw_cb: tty_ctx_redraw_cb,
1836    set_client_cb: tty_ctx_set_client_cb,
1837    arg: *mut c_void,
1838
1839    cell: *const grid_cell,
1840    wrapped: i32,
1841
1842    num: u32,
1843    ptr: *mut c_void,
1844    ptr2: *mut c_void,
1845
1846    allow_invisible_panes: i32,
1847
1848    /*
1849     * Cursor and region position before the screen was updated - this is
1850     * where the command should be applied; the values in the screen have
1851     * already been updated.
1852     */
1853    ocx: u32,
1854    ocy: u32,
1855
1856    orupper: u32,
1857    orlower: u32,
1858
1859    /* Target region (usually pane) offset and size. */
1860    xoff: u32,
1861    yoff: u32,
1862    rxoff: u32,
1863    ryoff: u32,
1864    sx: u32,
1865    sy: u32,
1866
1867    // The background colour used for clearing (erasing).
1868    bg: u32,
1869
1870    // The default colours and palette.
1871    defaults: grid_cell,
1872    palette: *const colour_palette,
1873
1874    // Containing region (usually window) offset and size.
1875    bigger: i32,
1876    wox: u32,
1877    woy: u32,
1878    wsx: u32,
1879    wsy: u32,
1880}
1881
1882// Saved message entry.
1883crate::compat::impl_tailq_entry!(message_entry, entry, tailq_entry<message_entry>);
1884// #[derive(Copy, Clone, crate::compat::TailQEntry)]
1885#[repr(C)]
1886struct message_entry {
1887    msg: *mut u8,
1888    msg_num: u32,
1889    msg_time: timeval,
1890
1891    // #[entry]
1892    entry: tailq_entry<message_entry>,
1893}
1894type message_list = tailq_head<message_entry>;
1895
1896/// Argument type.
1897#[repr(i32)]
1898#[derive(Copy, Clone, Eq, PartialEq)]
1899enum args_type {
1900    ARGS_NONE,
1901    ARGS_STRING,
1902    ARGS_COMMANDS,
1903}
1904
1905#[repr(C)]
1906union args_value_union {
1907    string: *mut u8,
1908    cmdlist: *mut cmd_list,
1909}
1910
1911/// Argument value.
1912crate::compat::impl_tailq_entry!(args_value, entry, tailq_entry<args_value>);
1913// #[derive(crate::compat::TailQEntry)]
1914#[repr(C)]
1915struct args_value {
1916    type_: args_type,
1917    union_: args_value_union,
1918    cached: *mut u8,
1919    // #[entry]
1920    entry: tailq_entry<args_value>,
1921}
1922type args_tree = rb_head<args_entry>;
1923
1924/// Arguments parsing type.
1925#[repr(C)]
1926#[derive(Copy, Clone, Eq, PartialEq)]
1927enum args_parse_type {
1928    ARGS_PARSE_INVALID,
1929    ARGS_PARSE_STRING,
1930    ARGS_PARSE_COMMANDS_OR_STRING,
1931    ARGS_PARSE_COMMANDS,
1932}
1933
1934type args_parse_cb = Option<unsafe fn(*mut args, u32, *mut *mut u8) -> args_parse_type>;
1935#[repr(C)]
1936struct args_parse {
1937    template: SyncCharPtr,
1938    lower: i32,
1939    upper: i32,
1940    cb: args_parse_cb,
1941}
1942
1943impl args_parse {
1944    const fn new(template: &'static CStr, lower: i32, upper: i32, cb: args_parse_cb) -> Self {
1945        Self {
1946            template: SyncCharPtr::new(template),
1947            lower,
1948            upper,
1949            cb,
1950        }
1951    }
1952}
1953
1954/// Command find structures.
1955#[repr(C)]
1956#[derive(Copy, Clone, Default)]
1957enum cmd_find_type {
1958    #[default]
1959    CMD_FIND_PANE,
1960    CMD_FIND_WINDOW,
1961    CMD_FIND_SESSION,
1962}
1963
1964#[repr(C)]
1965#[derive(Copy, Clone)]
1966struct cmd_find_state {
1967    flags: i32,
1968    current: *mut cmd_find_state,
1969
1970    s: *mut session,
1971    wl: *mut winlink,
1972    w: *mut window,
1973    wp: *mut window_pane,
1974    idx: i32,
1975}
1976
1977// Command find flags.
1978const CMD_FIND_PREFER_UNATTACHED: i32 = 0x1;
1979const CMD_FIND_QUIET: i32 = 0x2;
1980const CMD_FIND_WINDOW_INDEX: i32 = 0x4;
1981const CMD_FIND_DEFAULT_MARKED: i32 = 0x8;
1982const CMD_FIND_EXACT_SESSION: i32 = 0x10;
1983const CMD_FIND_EXACT_WINDOW: i32 = 0x20;
1984const CMD_FIND_CANFAIL: i32 = 0x40;
1985
1986/// List of commands.
1987#[repr(C)]
1988struct cmd_list {
1989    references: i32,
1990    group: u32,
1991    list: *mut cmds,
1992}
1993
1994/* Command return values. */
1995#[repr(i32)]
1996#[derive(Copy, Clone, Eq, PartialEq)]
1997enum cmd_retval {
1998    CMD_RETURN_ERROR = -1,
1999    CMD_RETURN_NORMAL = 0,
2000    CMD_RETURN_WAIT,
2001    CMD_RETURN_STOP,
2002}
2003
2004// Command parse result.
2005#[repr(i32)]
2006#[derive(Copy, Clone, Default, Eq, PartialEq)]
2007enum cmd_parse_status {
2008    #[default]
2009    CMD_PARSE_ERROR,
2010    CMD_PARSE_SUCCESS,
2011}
2012
2013type cmd_parse_result = Result<*mut cmd_list /* cmdlist */, *mut u8 /* error */>;
2014
2015bitflags::bitflags! {
2016    #[repr(transparent)]
2017    #[derive(Copy, Clone, Eq, PartialEq)]
2018    struct cmd_parse_input_flags: i32 {
2019        const CMD_PARSE_QUIET = 0x1;
2020        const CMD_PARSE_PARSEONLY = 0x2;
2021        const CMD_PARSE_NOALIAS = 0x4;
2022        const CMD_PARSE_VERBOSE = 0x8;
2023        const CMD_PARSE_ONEGROUP = 0x10;
2024    }
2025}
2026
2027#[repr(transparent)]
2028struct AtomicCmdParseInputFlags(std::sync::atomic::AtomicI32);
2029impl From<cmd_parse_input_flags> for AtomicCmdParseInputFlags {
2030    fn from(value: cmd_parse_input_flags) -> Self {
2031        Self(std::sync::atomic::AtomicI32::new(value.bits()))
2032    }
2033}
2034impl AtomicCmdParseInputFlags {
2035    fn intersects(&self, rhs: cmd_parse_input_flags) -> bool {
2036        cmd_parse_input_flags::from_bits(self.0.load(std::sync::atomic::Ordering::SeqCst))
2037            .unwrap()
2038            .intersects(rhs)
2039    }
2040}
2041impl std::ops::BitOrAssign<cmd_parse_input_flags> for &AtomicCmdParseInputFlags {
2042    fn bitor_assign(&mut self, rhs: cmd_parse_input_flags) {
2043        self.0
2044            .fetch_or(rhs.bits(), std::sync::atomic::Ordering::SeqCst);
2045    }
2046}
2047impl std::ops::BitAndAssign<cmd_parse_input_flags> for &AtomicCmdParseInputFlags {
2048    fn bitand_assign(&mut self, rhs: cmd_parse_input_flags) {
2049        self.0
2050            .fetch_and(rhs.bits(), std::sync::atomic::Ordering::SeqCst);
2051    }
2052}
2053
2054#[repr(C)]
2055struct cmd_parse_input<'a> {
2056    flags: AtomicCmdParseInputFlags,
2057
2058    file: Option<&'a str>,
2059    line: AtomicU32, // work around borrow checker
2060
2061    item: *mut cmdq_item,
2062    c: *mut client,
2063    fs: cmd_find_state,
2064}
2065
2066/// Command queue flags.
2067bitflags::bitflags! {
2068    #[repr(transparent)]
2069    #[derive(Copy, Clone, Eq, PartialEq)]
2070    struct cmdq_state_flags: i32 {
2071        const CMDQ_STATE_REPEAT = 0x1;
2072        const CMDQ_STATE_CONTROL = 0x2;
2073        const CMDQ_STATE_NOHOOKS = 0x4;
2074    }
2075}
2076
2077// Command queue callback.
2078type cmdq_cb = Option<unsafe fn(*mut cmdq_item, *mut c_void) -> cmd_retval>;
2079
2080// Command definition flag.
2081#[repr(C)]
2082#[derive(Copy, Clone, Default)]
2083struct cmd_entry_flag {
2084    flag: u8,
2085    type_: cmd_find_type,
2086    flags: i32,
2087}
2088
2089impl cmd_entry_flag {
2090    const fn new(flag: u8, type_: cmd_find_type, flags: i32) -> Self {
2091        Self { flag, type_, flags }
2092    }
2093
2094    const fn zeroed() -> Self {
2095        Self {
2096            flag: b'\0',
2097            type_: cmd_find_type::CMD_FIND_PANE,
2098            flags: 0,
2099        }
2100    }
2101}
2102
2103bitflags::bitflags! {
2104    #[repr(transparent)]
2105    #[derive(Copy, Clone, Eq, PartialEq)]
2106    struct cmd_flag: i32 {
2107        const CMD_STARTSERVER = 0x1;
2108        const CMD_READONLY = 0x2;
2109        const CMD_AFTERHOOK = 0x4;
2110        const CMD_CLIENT_CFLAG = 0x8;
2111        const CMD_CLIENT_TFLAG = 0x10;
2112        const CMD_CLIENT_CANFAIL = 0x20;
2113    }
2114}
2115
2116// Command definition.
2117#[repr(C)]
2118struct cmd_entry {
2119    name: SyncCharPtr,
2120    alias: SyncCharPtr,
2121
2122    args: args_parse,
2123    usage: SyncCharPtr,
2124
2125    source: cmd_entry_flag,
2126    target: cmd_entry_flag,
2127
2128    flags: cmd_flag,
2129
2130    exec: unsafe fn(*mut cmd, *mut cmdq_item) -> cmd_retval,
2131}
2132
2133/* Status line. */
2134const STATUS_LINES_LIMIT: usize = 5;
2135#[repr(C)]
2136struct status_line_entry {
2137    expanded: *mut u8,
2138    ranges: style_ranges,
2139}
2140#[repr(C)]
2141struct status_line {
2142    timer: event,
2143
2144    screen: screen,
2145    active: *mut screen,
2146    references: c_int,
2147
2148    style: grid_cell,
2149    entries: [status_line_entry; STATUS_LINES_LIMIT],
2150}
2151
2152/* Prompt type. */
2153const PROMPT_NTYPES: u32 = 4;
2154#[repr(u32)]
2155#[derive(Copy, Clone, Eq, PartialEq, num_enum::TryFromPrimitive)]
2156enum prompt_type {
2157    PROMPT_TYPE_COMMAND,
2158    PROMPT_TYPE_SEARCH,
2159    PROMPT_TYPE_TARGET,
2160    PROMPT_TYPE_WINDOW_TARGET,
2161    PROMPT_TYPE_INVALID = 0xff,
2162}
2163
2164/* File in client. */
2165type client_file_cb = Option<unsafe fn(*mut client, *mut u8, i32, i32, *mut evbuffer, *mut c_void)>;
2166#[repr(C)]
2167struct client_file {
2168    c: *mut client,
2169    peer: *mut tmuxpeer,
2170    tree: *mut client_files,
2171
2172    references: i32,
2173    stream: i32,
2174
2175    path: *mut u8,
2176    buffer: *mut evbuffer,
2177    event: *mut bufferevent,
2178
2179    fd: i32,
2180    error: i32,
2181    closed: i32,
2182
2183    cb: client_file_cb,
2184    data: *mut c_void,
2185
2186    entry: rb_entry<client_file>,
2187}
2188type client_files = rb_head<client_file>;
2189RB_GENERATE!(client_files, client_file, entry, discr_entry, file_cmp);
2190
2191// Client window.
2192#[repr(C)]
2193struct client_window {
2194    window: u32,
2195    pane: *mut window_pane,
2196
2197    sx: u32,
2198    sy: u32,
2199
2200    entry: rb_entry<client_window>,
2201}
2202type client_windows = rb_head<client_window>;
2203RB_GENERATE!(
2204    client_windows,
2205    client_window,
2206    entry,
2207    discr_entry,
2208    server_client_window_cmp
2209);
2210
2211/* Visible areas not obstructed by overlays. */
2212const OVERLAY_MAX_RANGES: usize = 3;
2213#[repr(C)]
2214struct overlay_ranges {
2215    px: [u32; OVERLAY_MAX_RANGES],
2216    nx: [u32; OVERLAY_MAX_RANGES],
2217}
2218
2219type prompt_input_cb = Option<unsafe fn(*mut client, NonNull<c_void>, *const u8, i32) -> i32>;
2220type prompt_free_cb = Option<unsafe fn(NonNull<c_void>)>;
2221type overlay_check_cb =
2222    Option<unsafe fn(*mut client, *mut c_void, u32, u32, u32, *mut overlay_ranges)>;
2223type overlay_mode_cb =
2224    Option<unsafe fn(*mut client, *mut c_void, *mut u32, *mut u32) -> *mut screen>;
2225type overlay_draw_cb = Option<unsafe fn(*mut client, *mut c_void, *mut screen_redraw_ctx)>;
2226type overlay_key_cb = Option<unsafe fn(*mut client, *mut c_void, *mut key_event) -> i32>;
2227type overlay_free_cb = Option<unsafe fn(*mut client, *mut c_void)>;
2228type overlay_resize_cb = Option<unsafe fn(*mut client, *mut c_void)>;
2229
2230bitflags::bitflags! {
2231    #[repr(transparent)]
2232    #[derive(Copy, Clone, Eq, PartialEq)]
2233    struct client_flag: u64 {
2234        const TERMINAL           = 0x0000000001u64;
2235        const LOGIN              = 0x0000000002u64;
2236        const EXIT               = 0x0000000004u64;
2237        const REDRAWWINDOW       = 0x0000000008u64;
2238        const REDRAWSTATUS       = 0x0000000010u64;
2239        const REPEAT             = 0x0000000020u64;
2240        const SUSPENDED          = 0x0000000040u64;
2241        const ATTACHED           = 0x0000000080u64;
2242        const EXITED             = 0x0000000100u64;
2243        const DEAD               = 0x0000000200u64;
2244        const REDRAWBORDERS      = 0x0000000400u64;
2245        const READONLY           = 0x0000000800u64;
2246        const NOSTARTSERVER      = 0x0000001000u64;
2247        const CONTROL            = 0x0000002000u64;
2248        const CONTROLCONTROL     = 0x0000004000u64;
2249        const FOCUSED            = 0x0000008000u64;
2250        const UTF8               = 0x0000010000u64;
2251        const IGNORESIZE         = 0x0000020000u64;
2252        const IDENTIFIED         = 0x0000040000u64;
2253        const STATUSFORCE        = 0x0000080000u64;
2254        const DOUBLECLICK        = 0x0000100000u64;
2255        const TRIPLECLICK        = 0x0000200000u64;
2256        const SIZECHANGED        = 0x0000400000u64;
2257        const STATUSOFF          = 0x0000800000u64;
2258        const REDRAWSTATUSALWAYS = 0x0001000000u64;
2259        const REDRAWOVERLAY      = 0x0002000000u64;
2260        const CONTROL_NOOUTPUT   = 0x0004000000u64;
2261        const DEFAULTSOCKET      = 0x0008000000u64;
2262        const STARTSERVER        = 0x0010000000u64;
2263        const REDRAWPANES        = 0x0020000000u64;
2264        const NOFORK             = 0x0040000000u64;
2265        const ACTIVEPANE         = 0x0080000000u64;
2266        const CONTROL_PAUSEAFTER = 0x0100000000u64;
2267        const CONTROL_WAITEXIT   = 0x0200000000u64;
2268        const WINDOWSIZECHANGED  = 0x0400000000u64;
2269        const CLIPBOARDBUFFER    = 0x0800000000u64;
2270        const BRACKETPASTING     = 0x1000000000u64;
2271    }
2272}
2273
2274const CLIENT_ALLREDRAWFLAGS: client_flag = client_flag::REDRAWWINDOW
2275    .union(client_flag::REDRAWSTATUS)
2276    .union(client_flag::REDRAWSTATUSALWAYS)
2277    .union(client_flag::REDRAWBORDERS)
2278    .union(client_flag::REDRAWOVERLAY)
2279    .union(client_flag::REDRAWPANES);
2280const CLIENT_UNATTACHEDFLAGS: client_flag = client_flag::DEAD
2281    .union(client_flag::SUSPENDED)
2282    .union(client_flag::EXIT);
2283const CLIENT_NODETACHFLAGS: client_flag = client_flag::DEAD.union(client_flag::EXIT);
2284const CLIENT_NOSIZEFLAGS: client_flag = client_flag::DEAD
2285    .union(client_flag::SUSPENDED)
2286    .union(client_flag::EXIT);
2287
2288const PROMPT_SINGLE: i32 = 0x1;
2289const PROMPT_NUMERIC: i32 = 0x2;
2290const PROMPT_INCREMENTAL: i32 = 0x4;
2291const PROMPT_NOFORMAT: i32 = 0x8;
2292const PROMPT_KEY: i32 = 0x8;
2293
2294//#[derive(Copy, Clone)]
2295crate::compat::impl_tailq_entry!(client, entry, tailq_entry<client>);
2296// #[derive(crate::compat::TailQEntry)]
2297#[repr(C)]
2298struct client {
2299    name: *const u8,
2300    peer: *mut tmuxpeer,
2301    queue: *mut cmdq_list,
2302
2303    windows: client_windows,
2304
2305    control_state: *mut control_state,
2306    pause_age: c_uint,
2307
2308    pid: pid_t,
2309    fd: c_int,
2310    out_fd: c_int,
2311    event: event,
2312    retval: c_int,
2313
2314    creation_time: timeval,
2315    activity_time: timeval,
2316
2317    environ: *mut environ,
2318    jobs: *mut format_job_tree,
2319
2320    title: *mut u8,
2321    path: *mut u8,
2322    cwd: *const u8,
2323
2324    term_name: *mut u8,
2325    term_features: c_int,
2326    term_type: *mut u8,
2327    term_caps: *mut *mut u8,
2328    term_ncaps: c_uint,
2329
2330    ttyname: *mut u8,
2331    tty: tty,
2332
2333    written: usize,
2334    discarded: usize,
2335    redraw: usize,
2336
2337    repeat_timer: event,
2338
2339    click_timer: event,
2340    click_button: c_uint,
2341    click_event: mouse_event,
2342
2343    status: status_line,
2344
2345    flags: client_flag,
2346
2347    exit_type: exit_type,
2348    exit_msgtype: msgtype,
2349    exit_session: *mut u8,
2350    exit_message: *mut u8,
2351
2352    keytable: *mut key_table,
2353
2354    redraw_panes: u64,
2355
2356    message_ignore_keys: c_int,
2357    message_ignore_styles: c_int,
2358    message_string: *mut u8,
2359    message_timer: event,
2360
2361    prompt_string: *mut u8,
2362    prompt_buffer: *mut utf8_data,
2363    prompt_last: *mut u8,
2364    prompt_index: usize,
2365    prompt_inputcb: prompt_input_cb,
2366    prompt_freecb: prompt_free_cb,
2367    prompt_data: *mut c_void,
2368    prompt_hindex: [c_uint; 4],
2369    prompt_mode: prompt_mode,
2370    prompt_saved: *mut utf8_data,
2371
2372    prompt_flags: c_int,
2373    prompt_type: prompt_type,
2374    prompt_cursor: c_int,
2375
2376    session: *mut session,
2377    last_session: *mut session,
2378
2379    references: c_int,
2380
2381    pan_window: *mut c_void,
2382    pan_ox: c_uint,
2383    pan_oy: c_uint,
2384
2385    overlay_check: overlay_check_cb,
2386    overlay_mode: overlay_mode_cb,
2387    overlay_draw: overlay_draw_cb,
2388    overlay_key: overlay_key_cb,
2389    overlay_free: overlay_free_cb,
2390    overlay_resize: overlay_resize_cb,
2391    overlay_data: *mut c_void,
2392    overlay_timer: event,
2393
2394    files: client_files,
2395
2396    clipboard_panes: *mut c_uint,
2397    clipboard_npanes: c_uint,
2398
2399    // #[entry]
2400    entry: tailq_entry<client>,
2401}
2402type clients = tailq_head<client>;
2403
2404/// Control mode subscription type.
2405#[repr(i32)]
2406enum control_sub_type {
2407    CONTROL_SUB_SESSION,
2408    CONTROL_SUB_PANE,
2409    CONTROL_SUB_ALL_PANES,
2410    CONTROL_SUB_WINDOW,
2411    CONTROL_SUB_ALL_WINDOWS,
2412}
2413
2414const KEY_BINDING_REPEAT: i32 = 0x1;
2415
2416/// Key binding and key table.
2417#[repr(C)]
2418struct key_binding {
2419    key: key_code,
2420    cmdlist: *mut cmd_list,
2421    note: *mut u8,
2422
2423    flags: i32,
2424
2425    entry: rb_entry<key_binding>,
2426}
2427type key_bindings = rb_head<key_binding>;
2428
2429#[repr(C)]
2430struct key_table {
2431    name: *mut u8,
2432    activity_time: timeval,
2433    key_bindings: key_bindings,
2434    default_key_bindings: key_bindings,
2435
2436    references: u32,
2437
2438    entry: rb_entry<key_table>,
2439}
2440type key_tables = rb_head<key_table>;
2441
2442// Option data.
2443type options_array = rb_head<options_array_item>;
2444
2445#[repr(C)]
2446#[derive(Copy, Clone)]
2447union options_value {
2448    string: *mut u8,
2449    number: c_longlong,
2450    style: style,
2451    array: options_array,
2452    cmdlist: *mut cmd_list,
2453}
2454
2455// Option table entries.
2456#[repr(i32)]
2457#[derive(Clone, Copy, PartialEq, Eq)]
2458enum options_table_type {
2459    OPTIONS_TABLE_STRING,
2460    OPTIONS_TABLE_NUMBER,
2461    OPTIONS_TABLE_KEY,
2462    OPTIONS_TABLE_COLOUR,
2463    OPTIONS_TABLE_FLAG,
2464    OPTIONS_TABLE_CHOICE,
2465    OPTIONS_TABLE_COMMAND,
2466}
2467
2468const OPTIONS_TABLE_NONE: i32 = 0;
2469const OPTIONS_TABLE_SERVER: i32 = 0x1;
2470const OPTIONS_TABLE_SESSION: i32 = 0x2;
2471const OPTIONS_TABLE_WINDOW: i32 = 0x4;
2472const OPTIONS_TABLE_PANE: i32 = 0x8;
2473
2474const OPTIONS_TABLE_IS_ARRAY: i32 = 0x1;
2475const OPTIONS_TABLE_IS_HOOK: i32 = 0x2;
2476const OPTIONS_TABLE_IS_STYLE: i32 = 0x4;
2477
2478#[repr(C)]
2479struct options_table_entry {
2480    name: *const u8,
2481    alternative_name: *mut u8,
2482    type_: options_table_type,
2483    scope: i32,
2484    flags: i32,
2485    minimum: u32,
2486    maximum: u32,
2487
2488    choices: *const *const u8,
2489
2490    default_str: Option<&'static str>,
2491    default_num: c_longlong,
2492    default_arr: *const *const u8,
2493
2494    separator: *const u8,
2495    pattern: *const u8,
2496
2497    text: *const u8,
2498    unit: *const u8,
2499}
2500
2501#[repr(C)]
2502struct options_name_map {
2503    from: *const u8,
2504    to: *const u8,
2505}
2506impl options_name_map {
2507    const fn new(from: *const u8, to: *const u8) -> Self {
2508        Self { from, to }
2509    }
2510}
2511
2512/* Common command usages. */
2513const CMD_TARGET_PANE_USAGE: &CStr = c"[-t target-pane]";
2514const CMD_TARGET_WINDOW_USAGE: &CStr = c"[-t target-window]";
2515const CMD_TARGET_SESSION_USAGE: &CStr = c"[-t target-session]";
2516const CMD_TARGET_CLIENT_USAGE: &CStr = c"[-t target-client]";
2517const CMD_SRCDST_PANE_USAGE: &CStr = c"[-s src-pane] [-t dst-pane]";
2518const CMD_SRCDST_WINDOW_USAGE: &CStr = c"[-s src-window] [-t dst-window]";
2519const CMD_SRCDST_SESSION_USAGE: &CStr = c"[-s src-session] [-t dst-session]";
2520const CMD_SRCDST_CLIENT_USAGE: &CStr = c"[-s src-client] [-t dst-client]";
2521const CMD_BUFFER_USAGE: &CStr = c"[-b buffer-name]";
2522
2523const SPAWN_KILL: i32 = 0x1;
2524const SPAWN_DETACHED: i32 = 0x2;
2525const SPAWN_RESPAWN: i32 = 0x4;
2526const SPAWN_BEFORE: i32 = 0x8;
2527const SPAWN_NONOTIFY: i32 = 0x10;
2528const SPAWN_FULLSIZE: i32 = 0x20;
2529const SPAWN_EMPTY: i32 = 0x40;
2530const SPAWN_ZOOM: i32 = 0x80;
2531
2532/// Spawn common context.
2533#[repr(C)]
2534struct spawn_context {
2535    item: *mut cmdq_item,
2536
2537    s: *mut session,
2538    wl: *mut winlink,
2539    tc: *mut client,
2540
2541    wp0: *mut window_pane,
2542    lc: *mut layout_cell,
2543
2544    name: *const u8,
2545    argv: *mut *mut u8,
2546    argc: i32,
2547    environ: *mut environ,
2548
2549    idx: i32,
2550    cwd: *const u8,
2551
2552    flags: i32,
2553}
2554
2555/// Mode tree sort order.
2556#[repr(C)]
2557struct mode_tree_sort_criteria {
2558    field: u32,
2559    reversed: i32,
2560}
2561
2562const WINDOW_MINIMUM: u32 = PANE_MINIMUM;
2563const WINDOW_MAXIMUM: u32 = 10_000;
2564
2565#[repr(i32)]
2566enum exit_type {
2567    CLIENT_EXIT_RETURN,
2568    CLIENT_EXIT_SHUTDOWN,
2569    CLIENT_EXIT_DETACH,
2570}
2571
2572#[repr(i32)]
2573#[derive(Copy, Clone, Eq, PartialEq)]
2574enum prompt_mode {
2575    PROMPT_ENTRY,
2576    PROMPT_COMMAND,
2577}
2578
2579mod tmux;
2580
2581pub use crate::tmux::tmux_main;
2582
2583use crate::tmux::{
2584    GLOBAL_ENVIRON, GLOBAL_OPTIONS, GLOBAL_S_OPTIONS, GLOBAL_W_OPTIONS, PTM_FD, SHELL_COMMAND,
2585    SOCKET_PATH, START_TIME, checkshell, find_cwd, find_home, get_timer, getversion, setblocking,
2586    shell_argv0,
2587};
2588
2589mod proc;
2590use crate::proc::{
2591    proc_add_peer, proc_clear_signals, proc_exit, proc_flush_peer, proc_fork_and_daemon,
2592    proc_get_peer_uid, proc_kill_peer, proc_loop, proc_remove_peer, proc_send, proc_set_signals,
2593    proc_start, proc_toggle_log, tmuxpeer, tmuxproc,
2594};
2595
2596mod cfg_;
2597use crate::cfg_::{
2598    CFG_CLIENT, CFG_FILES, CFG_FINISHED, CFG_NFILES, CFG_QUIET, cfg_print_causes, cfg_show_causes,
2599    load_cfg, load_cfg_from_buffer, start_cfg,
2600};
2601
2602mod paste;
2603use crate::paste::{
2604    paste_add, paste_buffer, paste_buffer_created, paste_buffer_data, paste_buffer_data_,
2605    paste_buffer_name, paste_buffer_order, paste_free, paste_get_name, paste_get_top,
2606    paste_is_empty, paste_make_sample, paste_rename, paste_replace, paste_set, paste_walk,
2607};
2608
2609mod format;
2610use crate::format::format_add;
2611use crate::format::{
2612    FORMAT_NONE, FORMAT_PANE, FORMAT_WINDOW, format_add_cb, format_add_tv, format_cb,
2613    format_create, format_create_defaults, format_create_from_state, format_create_from_target,
2614    format_defaults, format_defaults_pane, format_defaults_paste_buffer, format_defaults_window,
2615    format_each, format_expand, format_expand_time, format_flags, format_free, format_get_pane,
2616    format_grid_hyperlink, format_grid_line, format_grid_word, format_job_tree, format_log_debug,
2617    format_lost_client, format_merge, format_pretty_time, format_single, format_single_from_state,
2618    format_single_from_target, format_skip, format_tidy_jobs, format_tree, format_true,
2619};
2620
2621mod format_draw_;
2622use crate::format_draw_::{format_draw, format_trim_left, format_trim_right, format_width};
2623
2624mod notify;
2625use crate::notify::{
2626    notify_client, notify_hook, notify_pane, notify_paste_buffer, notify_session,
2627    notify_session_window, notify_window, notify_winlink,
2628};
2629
2630mod options_;
2631use crate::options_::options_set_string;
2632use crate::options_::{
2633    options, options_array_assign, options_array_clear, options_array_first, options_array_get,
2634    options_array_item, options_array_item_index, options_array_item_value, options_array_next,
2635    options_array_set, options_create, options_default, options_default_to_string, options_empty,
2636    options_entry, options_first, options_free, options_from_string, options_get,
2637    options_get_number, options_get_number_, options_get_only, options_get_parent,
2638    options_get_string, options_get_string_, options_is_array, options_is_string, options_match,
2639    options_match_get, options_name, options_next, options_owner, options_parse, options_parse_get,
2640    options_push_changes, options_remove_or_default, options_scope_from_flags,
2641    options_scope_from_name, options_set_number, options_set_parent, options_string_to_style,
2642    options_table_entry, options_to_string,
2643};
2644
2645mod options_table;
2646use crate::options_table::{OPTIONS_OTHER_NAMES, OPTIONS_TABLE};
2647
2648bitflags::bitflags! {
2649    #[repr(transparent)]
2650    #[derive(Copy, Clone, Eq, PartialEq)]
2651    struct job_flag: i32 {
2652        const JOB_NOWAIT = 1;
2653        const JOB_KEEPWRITE = 2;
2654        const JOB_PTY = 4;
2655        const JOB_DEFAULTSHELL = 8;
2656    }
2657}
2658mod job_;
2659use crate::job_::{
2660    job, job_check_died, job_complete_cb, job_free, job_free_cb, job_get_data, job_get_event,
2661    job_get_status, job_kill_all, job_print_summary, job_resize, job_run, job_still_running,
2662    job_transfer, job_update_cb,
2663};
2664
2665mod environ_;
2666use crate::environ_::{
2667    environ, environ_clear, environ_copy, environ_create, environ_find, environ_first,
2668    environ_for_session, environ_free, environ_next, environ_push, environ_put, environ_unset,
2669    environ_update,
2670};
2671use crate::environ_::{environ_log, environ_set};
2672
2673mod tty_;
2674use crate::tty_::{
2675    tty_attributes, tty_cell, tty_clipboard_query, tty_close, tty_cmd_alignmenttest, tty_cmd_cell,
2676    tty_cmd_cells, tty_cmd_clearcharacter, tty_cmd_clearendofline, tty_cmd_clearendofscreen,
2677    tty_cmd_clearline, tty_cmd_clearscreen, tty_cmd_clearstartofline, tty_cmd_clearstartofscreen,
2678    tty_cmd_deletecharacter, tty_cmd_deleteline, tty_cmd_insertcharacter, tty_cmd_insertline,
2679    tty_cmd_linefeed, tty_cmd_rawstring, tty_cmd_reverseindex, tty_cmd_scrolldown,
2680    tty_cmd_scrollup, tty_cmd_setselection, tty_cmd_syncstart, tty_create_log, tty_cursor,
2681    tty_default_colours, tty_draw_line, tty_free, tty_init, tty_margin_off, tty_open, tty_putc,
2682    tty_putcode, tty_putcode_i, tty_putcode_ii, tty_putcode_iii, tty_putcode_s, tty_putcode_ss,
2683    tty_putn, tty_puts, tty_raw, tty_region_off, tty_repeat_requests, tty_reset, tty_resize,
2684    tty_send_requests, tty_set_path, tty_set_selection, tty_set_size, tty_set_title, tty_start_tty,
2685    tty_stop_tty, tty_sync_end, tty_sync_start, tty_update_client_offset, tty_update_features,
2686    tty_update_mode, tty_update_window_offset, tty_window_bigger, tty_window_offset, tty_write,
2687};
2688
2689mod tty_term_;
2690use crate::tty_term_::{
2691    TTY_TERMS, tty_code, tty_term_apply, tty_term_apply_overrides, tty_term_create,
2692    tty_term_describe, tty_term_flag, tty_term_free, tty_term_free_list, tty_term_has,
2693    tty_term_ncodes, tty_term_number, tty_term_read_list, tty_term_string, tty_term_string_i,
2694    tty_term_string_ii, tty_term_string_iii, tty_term_string_s, tty_term_string_ss,
2695};
2696
2697mod tty_features;
2698use crate::tty_features::{
2699    tty_add_features, tty_apply_features, tty_default_features, tty_get_features,
2700};
2701
2702mod tty_acs;
2703use crate::tty_acs::{
2704    tty_acs_double_borders, tty_acs_get, tty_acs_heavy_borders, tty_acs_needed,
2705    tty_acs_reverse_get, tty_acs_rounded_borders,
2706};
2707
2708mod tty_keys;
2709use crate::tty_keys::{tty_key, tty_keys_build, tty_keys_colours, tty_keys_free, tty_keys_next};
2710
2711mod arguments;
2712
2713// TODO convert calls to args_has to args_has_
2714unsafe fn args_has_(args: *mut args, flag: char) -> bool {
2715    debug_assert!(flag.is_ascii());
2716    unsafe { args_has(args, flag as u8) != 0 }
2717}
2718
2719// unsafe fn args_get(_: *mut args, _: c_uchar) -> *const c_char;
2720unsafe fn args_get_(args: *mut args, flag: char) -> *const u8 {
2721    debug_assert!(flag.is_ascii());
2722    unsafe { args_get(args, flag as u8) }
2723}
2724
2725use crate::arguments::{
2726    args, args_command_state, args_copy, args_count, args_create, args_entry, args_escape,
2727    args_first, args_first_value, args_free, args_free_value, args_free_values, args_from_vector,
2728    args_get, args_has, args_make_commands, args_make_commands_free,
2729    args_make_commands_get_command, args_make_commands_now, args_make_commands_prepare, args_next,
2730    args_next_value, args_parse, args_percentage, args_percentage_and_expand, args_print, args_set,
2731    args_string, args_string_percentage, args_string_percentage_and_expand, args_strtonum,
2732    args_strtonum_and_expand, args_to_vector, args_value, args_values,
2733};
2734
2735mod cmd_;
2736use crate::cmd_::cmd_log_argv;
2737use crate::cmd_::{
2738    CMD_TABLE, cmd, cmd_append_argv, cmd_copy, cmd_copy_argv, cmd_free, cmd_free_argv,
2739    cmd_get_alias, cmd_get_args, cmd_get_entry, cmd_get_group, cmd_get_source, cmd_list_all_have,
2740    cmd_list_any_have, cmd_list_append, cmd_list_append_all, cmd_list_copy, cmd_list_first,
2741    cmd_list_free, cmd_list_move, cmd_list_new, cmd_list_next, cmd_list_print, cmd_mouse_at,
2742    cmd_mouse_pane, cmd_mouse_window, cmd_pack_argv, cmd_parse, cmd_print, cmd_stringify_argv,
2743    cmd_template_replace, cmd_unpack_argv, cmds,
2744};
2745
2746use crate::cmd_::cmd_attach_session::cmd_attach_session;
2747
2748use crate::cmd_::cmd_find::{
2749    cmd_find_best_client, cmd_find_clear_state, cmd_find_client, cmd_find_copy_state,
2750    cmd_find_empty_state, cmd_find_from_client, cmd_find_from_mouse, cmd_find_from_nothing,
2751    cmd_find_from_pane, cmd_find_from_session, cmd_find_from_session_window, cmd_find_from_window,
2752    cmd_find_from_winlink, cmd_find_from_winlink_pane, cmd_find_target, cmd_find_valid_state,
2753};
2754
2755mod cmd_parse;
2756use crate::cmd_parse::{
2757    cmd_parse_and_append, cmd_parse_and_insert, cmd_parse_command, cmd_parse_from_arguments,
2758    cmd_parse_from_buffer, cmd_parse_from_file, cmd_parse_from_string, cmd_parse_state, *,
2759};
2760
2761use crate::cmd_::cmd_queue::{
2762    cmdq_add_format, cmdq_add_formats, cmdq_append, cmdq_continue, cmdq_copy_state, cmdq_error,
2763    cmdq_free, cmdq_free_state, cmdq_get_callback, cmdq_get_callback1, cmdq_get_client,
2764    cmdq_get_command, cmdq_get_current, cmdq_get_error, cmdq_get_event, cmdq_get_flags,
2765    cmdq_get_name, cmdq_get_source, cmdq_get_state, cmdq_get_target, cmdq_get_target_client,
2766    cmdq_guard, cmdq_insert_after, cmdq_insert_hook, cmdq_item, cmdq_link_state, cmdq_list,
2767    cmdq_merge_formats, cmdq_new, cmdq_new_state, cmdq_next, cmdq_print, cmdq_print_data,
2768    cmdq_running, cmdq_state,
2769};
2770
2771use crate::cmd_::cmd_wait_for::cmd_wait_for_flush;
2772
2773mod client_;
2774use crate::client_::client_main;
2775
2776mod key_bindings_;
2777use crate::key_bindings_::{
2778    key_bindings_add, key_bindings_dispatch, key_bindings_first, key_bindings_first_table,
2779    key_bindings_get, key_bindings_get_default, key_bindings_get_table, key_bindings_init,
2780    key_bindings_next, key_bindings_next_table, key_bindings_remove, key_bindings_remove_table,
2781    key_bindings_reset, key_bindings_reset_table, key_bindings_unref_table,
2782};
2783
2784mod key_string;
2785use crate::key_string::{key_string_lookup_key, key_string_lookup_string};
2786
2787mod alerts;
2788use crate::alerts::{alerts_check_session, alerts_queue, alerts_reset_all};
2789
2790mod file;
2791use crate::file::{
2792    file_can_print, file_cancel, file_cmp, file_create_with_client, file_create_with_peer,
2793    file_error, file_fire_done, file_fire_read, file_free, file_print, file_print_buffer,
2794    file_push, file_read, file_read_cancel, file_read_data, file_read_done, file_read_open,
2795    file_vprint, file_write, file_write_close, file_write_data, file_write_left, file_write_open,
2796    file_write_ready,
2797};
2798
2799mod server;
2800use crate::server::{
2801    CLIENTS, CURRENT_TIME, MARKED_PANE, MESSAGE_LOG, SERVER_PROC, server_add_accept,
2802    server_add_message, server_check_marked, server_clear_marked, server_create_socket,
2803    server_is_marked, server_set_marked, server_start, server_update_socket,
2804};
2805
2806mod server_client;
2807use crate::server_client::{
2808    server_client_add_client_window, server_client_check_nested, server_client_clear_overlay,
2809    server_client_create, server_client_detach, server_client_exec,
2810    server_client_get_client_window, server_client_get_cwd, server_client_get_flags,
2811    server_client_get_key_table, server_client_get_pane, server_client_handle_key,
2812    server_client_how_many, server_client_loop, server_client_lost, server_client_open,
2813    server_client_overlay_range, server_client_print, server_client_remove_pane,
2814    server_client_set_flags, server_client_set_key_table, server_client_set_overlay,
2815    server_client_set_pane, server_client_set_session, server_client_suspend, server_client_unref,
2816    server_client_window_cmp,
2817};
2818
2819mod server_fn;
2820use crate::server_fn::{
2821    server_check_unattached, server_destroy_pane, server_destroy_session, server_kill_pane,
2822    server_kill_window, server_link_window, server_lock, server_lock_client, server_lock_session,
2823    server_redraw_client, server_redraw_session, server_redraw_session_group, server_redraw_window,
2824    server_redraw_window_borders, server_renumber_all, server_renumber_session,
2825    server_status_client, server_status_session, server_status_session_group, server_status_window,
2826    server_unlink_window, server_unzoom_window,
2827};
2828
2829mod status;
2830use crate::status::{
2831    STATUS_PROMPT_HLIST, STATUS_PROMPT_HSIZE, status_at_line, status_free, status_get_range,
2832    status_init, status_line_size, status_message_clear, status_message_redraw, status_message_set,
2833    status_prompt_clear, status_prompt_key, status_prompt_load_history, status_prompt_redraw,
2834    status_prompt_save_history, status_prompt_set, status_prompt_type, status_prompt_type_string,
2835    status_prompt_update, status_redraw, status_timer_start, status_timer_start_all,
2836    status_update_cache,
2837};
2838
2839mod resize;
2840use crate::resize::{
2841    default_window_size, recalculate_size, recalculate_sizes, recalculate_sizes_now, resize_window,
2842};
2843
2844mod input;
2845use crate::input::{
2846    input_ctx, input_free, input_init, input_parse_buffer, input_parse_pane, input_parse_screen,
2847    input_pending, input_reply_clipboard, input_reset,
2848};
2849
2850mod input_keys;
2851use crate::input_keys::{input_key, input_key_build, input_key_get_mouse, input_key_pane};
2852
2853mod colour;
2854use crate::colour::{
2855    colour_256to16, colour_byname, colour_find_rgb, colour_force_rgb, colour_fromstring,
2856    colour_fromstring_, colour_join_rgb, colour_palette_clear, colour_palette_free,
2857    colour_palette_from_option, colour_palette_get, colour_palette_init, colour_palette_set,
2858    colour_parse_x11, colour_split_rgb, colour_tostring,
2859};
2860
2861mod attributes;
2862use crate::attributes::{attributes_fromstring, attributes_tostring};
2863
2864mod grid_;
2865use crate::grid_::{
2866    GRID_DEFAULT_CELL, grid_adjust_lines, grid_cells_equal, grid_cells_look_equal, grid_clear,
2867    grid_clear_history, grid_clear_lines, grid_collect_history, grid_compare, grid_create,
2868    grid_destroy, grid_duplicate_lines, grid_empty_line, grid_get_cell, grid_get_line,
2869    grid_line_length, grid_move_cells, grid_move_lines, grid_peek_line, grid_reflow,
2870    grid_remove_history, grid_scroll_history, grid_scroll_history_region, grid_set_cell,
2871    grid_set_cells, grid_set_padding, grid_string_cells, grid_unwrap_position, grid_wrap_position,
2872};
2873
2874mod grid_reader_;
2875use crate::grid_reader_::{
2876    grid_reader_cursor_back_to_indentation, grid_reader_cursor_down,
2877    grid_reader_cursor_end_of_line, grid_reader_cursor_jump, grid_reader_cursor_jump_back,
2878    grid_reader_cursor_left, grid_reader_cursor_next_word, grid_reader_cursor_next_word_end,
2879    grid_reader_cursor_previous_word, grid_reader_cursor_right, grid_reader_cursor_start_of_line,
2880    grid_reader_cursor_up, grid_reader_get_cursor, grid_reader_in_set, grid_reader_line_length,
2881    grid_reader_start,
2882};
2883
2884mod grid_view;
2885use crate::grid_view::{
2886    grid_view_clear, grid_view_clear_history, grid_view_delete_cells, grid_view_delete_lines,
2887    grid_view_delete_lines_region, grid_view_get_cell, grid_view_insert_cells,
2888    grid_view_insert_lines, grid_view_insert_lines_region, grid_view_scroll_region_down,
2889    grid_view_scroll_region_up, grid_view_set_cell, grid_view_set_cells, grid_view_set_padding,
2890    grid_view_string_cells,
2891};
2892
2893mod screen_write;
2894use crate::screen_write::{
2895    screen_write_alignmenttest, screen_write_alternateoff, screen_write_alternateon,
2896    screen_write_backspace, screen_write_box, screen_write_carriagereturn, screen_write_cell,
2897    screen_write_citem, screen_write_clearcharacter, screen_write_clearendofline,
2898    screen_write_clearendofscreen, screen_write_clearhistory, screen_write_clearline,
2899    screen_write_clearscreen, screen_write_clearstartofline, screen_write_clearstartofscreen,
2900    screen_write_cline, screen_write_collect_add, screen_write_collect_end,
2901    screen_write_cursordown, screen_write_cursorleft, screen_write_cursormove,
2902    screen_write_cursorright, screen_write_cursorup, screen_write_deletecharacter,
2903    screen_write_deleteline, screen_write_fast_copy, screen_write_free_list,
2904    screen_write_fullredraw, screen_write_hline, screen_write_insertcharacter,
2905    screen_write_insertline, screen_write_linefeed, screen_write_make_list, screen_write_menu,
2906    screen_write_mode_clear, screen_write_mode_set, screen_write_preview, screen_write_putc,
2907    screen_write_rawstring, screen_write_reset, screen_write_reverseindex, screen_write_scrolldown,
2908    screen_write_scrollregion, screen_write_scrollup, screen_write_setselection,
2909    screen_write_start, screen_write_start_callback, screen_write_start_pane, screen_write_stop,
2910    screen_write_vline,
2911};
2912use crate::screen_write::{
2913    screen_write_nputs, screen_write_puts, screen_write_strlen, screen_write_text,
2914    screen_write_vnputs, screen_write_vnputs_,
2915};
2916
2917mod screen_redraw;
2918use crate::screen_redraw::{screen_redraw_pane, screen_redraw_screen};
2919
2920mod screen_;
2921use crate::screen_::{
2922    screen_alternate_off, screen_alternate_on, screen_check_selection, screen_clear_selection,
2923    screen_free, screen_hide_selection, screen_init, screen_mode_to_string, screen_pop_title,
2924    screen_push_title, screen_reinit, screen_reset_hyperlinks, screen_reset_tabs, screen_resize,
2925    screen_resize_cursor, screen_sel, screen_select_cell, screen_set_cursor_colour,
2926    screen_set_cursor_style, screen_set_path, screen_set_selection, screen_set_title,
2927    screen_titles,
2928};
2929
2930mod window_;
2931use crate::window_::{
2932    ALL_WINDOW_PANES, WINDOWS, window_add_pane, window_add_ref, window_cmp, window_count_panes,
2933    window_create, window_destroy_panes, window_find_by_id, window_find_by_id_str,
2934    window_find_string, window_get_active_at, window_has_pane, window_lost_pane,
2935    window_pane_at_index, window_pane_cmp, window_pane_default_cursor, window_pane_destroy_ready,
2936    window_pane_exited, window_pane_find_by_id, window_pane_find_by_id_str, window_pane_find_down,
2937    window_pane_find_left, window_pane_find_right, window_pane_find_up, window_pane_get_new_data,
2938    window_pane_index, window_pane_key, window_pane_mode, window_pane_next_by_number,
2939    window_pane_previous_by_number, window_pane_reset_mode, window_pane_reset_mode_all,
2940    window_pane_resize, window_pane_search, window_pane_send_resize, window_pane_set_event,
2941    window_pane_set_mode, window_pane_stack_push, window_pane_stack_remove,
2942    window_pane_start_input, window_pane_update_focus, window_pane_update_used_data,
2943    window_pane_visible, window_pop_zoom, window_printable_flags, window_push_zoom,
2944    window_redraw_active_switch, window_remove_pane, window_remove_ref, window_resize,
2945    window_set_active_pane, window_set_fill_character, window_set_name, window_unzoom,
2946    window_update_activity, window_update_focus, window_zoom, winlink_add, winlink_clear_flags,
2947    winlink_cmp, winlink_count, winlink_find_by_index, winlink_find_by_window,
2948    winlink_find_by_window_id, winlink_next, winlink_next_by_number, winlink_previous,
2949    winlink_previous_by_number, winlink_remove, winlink_set_window, winlink_shuffle_up,
2950    winlink_stack_push, winlink_stack_remove,
2951};
2952
2953mod layout;
2954use crate::layout::{
2955    layout_assign_pane, layout_close_pane, layout_count_cells, layout_create_cell,
2956    layout_destroy_cell, layout_fix_offsets, layout_fix_panes, layout_free, layout_free_cell,
2957    layout_init, layout_make_leaf, layout_make_node, layout_print_cell, layout_resize,
2958    layout_resize_adjust, layout_resize_layout, layout_resize_pane, layout_resize_pane_to,
2959    layout_search_by_border, layout_set_size, layout_split_pane, layout_spread_cell,
2960    layout_spread_out,
2961};
2962
2963mod layout_custom;
2964use crate::layout_custom::{layout_dump, layout_parse};
2965
2966mod layout_set;
2967use crate::layout_set::{
2968    layout_set_lookup, layout_set_next, layout_set_previous, layout_set_select,
2969};
2970
2971mod mode_tree;
2972use crate::mode_tree::{
2973    mode_tree_add, mode_tree_build, mode_tree_build_cb, mode_tree_collapse_current,
2974    mode_tree_count_tagged, mode_tree_data, mode_tree_down, mode_tree_draw,
2975    mode_tree_draw_as_parent, mode_tree_draw_cb, mode_tree_each_cb, mode_tree_each_tagged,
2976    mode_tree_expand, mode_tree_expand_current, mode_tree_free, mode_tree_get_current,
2977    mode_tree_get_current_name, mode_tree_height_cb, mode_tree_item, mode_tree_key,
2978    mode_tree_key_cb, mode_tree_menu_cb, mode_tree_no_tag, mode_tree_remove, mode_tree_resize,
2979    mode_tree_run_command, mode_tree_search_cb, mode_tree_set_current, mode_tree_start,
2980    mode_tree_up, mode_tree_zoom,
2981};
2982
2983mod window_buffer;
2984use crate::window_buffer::WINDOW_BUFFER_MODE;
2985
2986mod window_tree;
2987use crate::window_tree::WINDOW_TREE_MODE;
2988
2989mod window_clock;
2990use crate::window_clock::{WINDOW_CLOCK_MODE, WINDOW_CLOCK_TABLE};
2991
2992mod window_client;
2993use crate::window_client::WINDOW_CLIENT_MODE;
2994
2995mod window_copy;
2996use crate::window_copy::window_copy_add;
2997use crate::window_copy::{
2998    WINDOW_COPY_MODE, WINDOW_VIEW_MODE, window_copy_get_line, window_copy_get_word,
2999    window_copy_pagedown, window_copy_pageup, window_copy_start_drag, window_copy_vadd,
3000};
3001
3002mod window_customize;
3003use crate::window_customize::WINDOW_CUSTOMIZE_MODE;
3004
3005mod names;
3006use crate::names::{check_window_name, default_window_name, parse_window_name};
3007
3008mod control;
3009use crate::control::control_write;
3010use crate::control::{
3011    control_add_sub, control_all_done, control_continue_pane, control_discard, control_pane_offset,
3012    control_pause_pane, control_ready, control_remove_sub, control_reset_offsets,
3013    control_set_pane_off, control_set_pane_on, control_start, control_state, control_stop,
3014    control_write_output,
3015};
3016
3017mod control_notify;
3018use crate::control_notify::{
3019    control_notify_client_detached, control_notify_client_session_changed,
3020    control_notify_pane_mode_changed, control_notify_paste_buffer_changed,
3021    control_notify_paste_buffer_deleted, control_notify_session_closed,
3022    control_notify_session_created, control_notify_session_renamed,
3023    control_notify_session_window_changed, control_notify_window_layout_changed,
3024    control_notify_window_linked, control_notify_window_pane_changed,
3025    control_notify_window_renamed, control_notify_window_unlinked,
3026};
3027
3028mod session_;
3029use crate::session_::{
3030    NEXT_SESSION_ID, SESSIONS, session_add_ref, session_alive, session_attach, session_check_name,
3031    session_cmp, session_create, session_destroy, session_detach, session_find, session_find_by_id,
3032    session_find_by_id_str, session_group_add, session_group_attached_count,
3033    session_group_contains, session_group_count, session_group_find, session_group_new,
3034    session_group_synchronize_from, session_group_synchronize_to, session_has, session_is_linked,
3035    session_last, session_next, session_next_session, session_previous, session_previous_session,
3036    session_remove_ref, session_renumber_windows, session_select, session_set_current,
3037    session_update_activity,
3038};
3039
3040mod utf8;
3041use crate::utf8::{
3042    utf8_append, utf8_build_one, utf8_copy, utf8_cstrhas, utf8_cstrwidth, utf8_from_data,
3043    utf8_fromcstr, utf8_fromwc, utf8_in_table, utf8_isvalid, utf8_open, utf8_padcstr,
3044    utf8_rpadcstr, utf8_sanitize, utf8_set, utf8_stravis, utf8_stravisx, utf8_strlen, utf8_strvis,
3045    utf8_strwidth, utf8_to_data, utf8_tocstr, utf8_towc,
3046};
3047
3048mod osdep;
3049use crate::osdep::{osdep_event_init, osdep_get_cwd, osdep_get_name};
3050
3051mod utf8_combined;
3052use crate::utf8_combined::{utf8_has_zwj, utf8_is_modifier, utf8_is_vs, utf8_is_zwj};
3053
3054// procname.c
3055unsafe extern "C" {
3056    unsafe fn get_proc_name(_: c_int, _: *mut u8) -> *mut u8;
3057    unsafe fn get_proc_cwd(_: c_int) -> *mut u8;
3058}
3059
3060#[macro_use] // log_debug
3061mod log;
3062use crate::log::{fatal, fatalx, log_add_level, log_close, log_get_level, log_open, log_toggle};
3063use crate::log::{fatalx_, log_debug};
3064
3065const MENU_NOMOUSE: i32 = 0x1;
3066const MENU_TAB: i32 = 0x2;
3067const MENU_STAYOPEN: i32 = 0x4;
3068mod menu_;
3069use crate::menu_::{
3070    menu_add_item, menu_add_items, menu_check_cb, menu_create, menu_data, menu_display,
3071    menu_draw_cb, menu_free, menu_free_cb, menu_key_cb, menu_mode_cb, menu_prepare,
3072};
3073
3074const POPUP_CLOSEEXIT: i32 = 0x1;
3075const POPUP_CLOSEEXITZERO: i32 = 0x2;
3076const POPUP_INTERNAL: i32 = 0x4;
3077mod popup;
3078use crate::popup::{popup_close_cb, popup_display, popup_editor, popup_finish_edit_cb};
3079
3080mod style_;
3081use crate::style_::{style_add, style_apply, style_copy, style_parse, style_set, style_tostring};
3082
3083mod spawn;
3084use crate::spawn::{spawn_pane, spawn_window};
3085
3086mod regsub;
3087use crate::regsub::regsub;
3088
3089/* image.c */
3090unsafe extern "C" {}
3091/* image-sixel.c */
3092unsafe extern "C" {}
3093
3094mod server_acl;
3095use crate::server_acl::{
3096    server_acl_display, server_acl_get_uid, server_acl_init, server_acl_join, server_acl_user,
3097    server_acl_user_allow, server_acl_user_allow_write, server_acl_user_deny,
3098    server_acl_user_deny_write, server_acl_user_find,
3099};
3100
3101mod hyperlinks_;
3102use crate::hyperlinks_::{
3103    hyperlinks, hyperlinks_copy, hyperlinks_free, hyperlinks_get, hyperlinks_init, hyperlinks_put,
3104    hyperlinks_reset, hyperlinks_uri,
3105};
3106
3107mod xmalloc;
3108use crate::xmalloc::{format_nul, xsnprintf_};
3109use crate::xmalloc::{
3110    xcalloc, xcalloc_, xcalloc1, xmalloc, xmalloc_, xrealloc, xrealloc_, xreallocarray_, xstrdup,
3111    xstrdup_, xstrdup__, xstrdup___,
3112};
3113
3114mod tmux_protocol;
3115use crate::tmux_protocol::{
3116    PROTOCOL_VERSION, msg_command, msg_read_cancel, msg_read_data, msg_read_done, msg_read_open,
3117    msg_write_close, msg_write_data, msg_write_open, msg_write_ready, msgtype,
3118};
3119
3120unsafe extern "C-unwind" {
3121    fn vsnprintf(_: *mut u8, _: usize, _: *const u8, _: ...) -> c_int;
3122    fn vasprintf(_: *mut *mut u8, _: *const u8, _: ...) -> c_int;
3123}
3124
3125unsafe impl Sync for SyncCharPtr {}
3126#[repr(transparent)]
3127#[derive(Copy, Clone)]
3128struct SyncCharPtr(*const u8);
3129impl SyncCharPtr {
3130    const fn new(value: &'static CStr) -> Self {
3131        Self(value.as_ptr().cast())
3132    }
3133    const fn from_ptr(value: *const u8) -> Self {
3134        Self(value)
3135    }
3136    const fn null() -> Self {
3137        Self(null())
3138    }
3139    const fn as_ptr(&self) -> *const u8 {
3140        self.0
3141    }
3142    const fn is_null(&self) -> bool {
3143        self.0.is_null()
3144    }
3145}
3146
3147unsafe fn _s(ptr: impl ToU8Ptr) -> DisplayCStrPtr {
3148    DisplayCStrPtr(ptr.to_u8_ptr())
3149}
3150trait ToU8Ptr {
3151    fn to_u8_ptr(self) -> *const u8;
3152}
3153impl ToU8Ptr for *mut u8 {
3154    fn to_u8_ptr(self) -> *const u8 {
3155        self.cast()
3156    }
3157}
3158impl ToU8Ptr for *const u8 {
3159    fn to_u8_ptr(self) -> *const u8 {
3160        self
3161    }
3162}
3163impl ToU8Ptr for *mut i8 {
3164    fn to_u8_ptr(self) -> *const u8 {
3165        self.cast()
3166    }
3167}
3168impl ToU8Ptr for *const i8 {
3169    fn to_u8_ptr(self) -> *const u8 {
3170        self.cast()
3171    }
3172}
3173impl ToU8Ptr for SyncCharPtr {
3174    fn to_u8_ptr(self) -> *const u8 {
3175        self.as_ptr()
3176    }
3177}
3178// TODO struct should have some sort of lifetime
3179/// Display wrapper for a *c_char pointer
3180#[repr(transparent)]
3181struct DisplayCStrPtr(*const u8);
3182impl DisplayCStrPtr {
3183    unsafe fn from_raw(s: *const u8) -> Self {
3184        Self(s)
3185    }
3186}
3187impl std::fmt::Display for DisplayCStrPtr {
3188    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3189        if self.0.is_null() {
3190            return f.write_str("(null)");
3191        }
3192
3193        // TODO alignment
3194
3195        let len = if let Some(width) = f.precision() {
3196            unsafe { libc::strnlen(self.0, width) }
3197        } else if let Some(width) = f.width() {
3198            unsafe { libc::strnlen(self.0, width) }
3199        } else {
3200            unsafe { libc::strlen(self.0) }
3201        };
3202
3203        let s: &[u8] = unsafe { std::slice::from_raw_parts(self.0, len) };
3204        let s = std::str::from_utf8(s).unwrap_or("%s-invalid-utf8");
3205        f.write_str(s)
3206    }
3207}
3208
3209// TOOD make usable in const context
3210// https://stackoverflow.com/a/63904992
3211macro_rules! function_name {
3212    () => {{
3213        fn f() {}
3214        fn type_name_of<T>(_: T) -> &'static str {
3215            std::any::type_name::<T>()
3216        }
3217        let name = type_name_of(f);
3218
3219        // Find and cut the rest of the path
3220        match &name[..name.len() - 3].rfind(':') {
3221            Some(pos) => &name[pos + 1..name.len() - 3],
3222            None => &name[..name.len() - 3],
3223        }
3224    }};
3225}
3226pub(crate) use function_name;
3227
3228const fn concat_array<const N: usize, const M: usize, const O: usize, T: Copy>(
3229    a1: [T; N],
3230    a2: [T; M],
3231) -> [T; O] {
3232    let mut out: [MaybeUninit<T>; O] = [MaybeUninit::uninit(); O];
3233
3234    let mut i: usize = 0;
3235    while i < a1.len() {
3236        out[i].write(a1[i]);
3237        i += 1;
3238    }
3239    while i < a1.len() + a2.len() {
3240        out[i].write(a2[i - a1.len()]);
3241        i += 1;
3242    }
3243
3244    assert!(a1.len() + a2.len() == out.len());
3245    assert!(i == out.len());
3246
3247    unsafe { std::mem::transmute_copy(&out) }
3248    // TODO once stabilized switch to:
3249    // unsafe { MaybeUninit::array_assume_init(out) }
3250}
3251
3252pub(crate) fn i32_to_ordering(value: i32) -> std::cmp::Ordering {
3253    match value {
3254        ..0 => std::cmp::Ordering::Less,
3255        0 => std::cmp::Ordering::Equal,
3256        1.. => std::cmp::Ordering::Greater,
3257    }
3258}
3259
3260pub(crate) unsafe fn cstr_to_str<'a>(ptr: *const u8) -> &'a str {
3261    unsafe {
3262        let len = libc::strlen(ptr);
3263
3264        let bytes = std::slice::from_raw_parts(ptr.cast::<u8>(), len);
3265
3266        std::str::from_utf8(bytes).expect("bad cstr_to_str")
3267    }
3268}
3269
3270// ideally we could just use c string literal until we transition to &str everywhere
3271// unfortunately, some platforms people use have
3272macro_rules! c {
3273    ($s:literal) => {{
3274        const S: &str = concat!($s, "\0");
3275        #[allow(unused_unsafe)]
3276        unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(S.as_bytes()) }
3277            .as_ptr()
3278            .cast::<u8>()
3279    }};
3280}
3281pub(crate) use c;