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