1/**
2 * @file modes.h
3 *
4 * Terminal mode utilities - pack and unpack ANSI/DEC mode identifiers.
5 */
6
7#ifndef GHOSTTY_VT_MODES_H
8#define GHOSTTY_VT_MODES_H
9
10/** @defgroup modes Mode Utilities
11 *
12 * Utilities for working with terminal modes. A mode is a compact
13 * 16-bit representation of a terminal mode identifier that encodes both
14 * the numeric mode value (up to 15 bits) and whether the mode is an ANSI
15 * mode or a DEC private mode (?-prefixed).
16 *
17 * The packed layout (least-significant bit first) is:
18 * - Bits 0–14: mode value (u15)
19 * - Bit 15: ANSI flag (0 = DEC private mode, 1 = ANSI mode)
20 *
21 * ## Example
22 *
23 * @snippet c-vt-modes/src/main.c modes-pack-unpack
24 *
25 * ## DECRPM Report Encoding
26 *
27 * Use ghostty_mode_report_encode() to encode a DECRPM response into a
28 * caller-provided buffer:
29 *
30 * @snippet c-vt-modes/src/main.c modes-decrpm
31 *
32 * @{
33 */
34
35#include <stdbool.h>
36#include <stddef.h>
37#include <stdint.h>
38
39#include <ghostty/vt/types.h>
40
41#ifdef __cplusplus
42extern "C" {
43#endif
44
45/** @name ANSI Modes
46 * Modes for standard ANSI modes.
47 * @{
48 */
49#define GHOSTTY_MODE_KAM (ghostty_mode_new(2, true)) /**< Keyboard action (disable keyboard) */
50#define GHOSTTY_MODE_INSERT (ghostty_mode_new(4, true)) /**< Insert mode */
51#define GHOSTTY_MODE_SRM (ghostty_mode_new(12, true)) /**< Send/receive mode */
52#define GHOSTTY_MODE_LINEFEED (ghostty_mode_new(20, true)) /**< Linefeed/new line mode */
53/** @} */
54
55/** @name DEC Private Modes
56 * Modes for DEC private modes (?-prefixed).
57 * @{
58 */
59#define GHOSTTY_MODE_DECCKM (ghostty_mode_new(1, false)) /**< Cursor keys */
60#define GHOSTTY_MODE_132_COLUMN (ghostty_mode_new(3, false)) /**< 132/80 column mode */
61#define GHOSTTY_MODE_SLOW_SCROLL (ghostty_mode_new(4, false)) /**< Slow scroll */
62#define GHOSTTY_MODE_REVERSE_COLORS (ghostty_mode_new(5, false)) /**< Reverse video */
63#define GHOSTTY_MODE_ORIGIN (ghostty_mode_new(6, false)) /**< Origin mode */
64#define GHOSTTY_MODE_WRAPAROUND (ghostty_mode_new(7, false)) /**< Auto-wrap mode */
65#define GHOSTTY_MODE_AUTOREPEAT (ghostty_mode_new(8, false)) /**< Auto-repeat keys */
66#define GHOSTTY_MODE_X10_MOUSE (ghostty_mode_new(9, false)) /**< X10 mouse reporting */
67#define GHOSTTY_MODE_CURSOR_BLINKING (ghostty_mode_new(12, false)) /**< Cursor blink */
68#define GHOSTTY_MODE_CURSOR_VISIBLE (ghostty_mode_new(25, false)) /**< Cursor visible (DECTCEM) */
69#define GHOSTTY_MODE_ENABLE_MODE_3 (ghostty_mode_new(40, false)) /**< Allow 132 column mode */
70#define GHOSTTY_MODE_REVERSE_WRAP (ghostty_mode_new(45, false)) /**< Reverse wrap */
71#define GHOSTTY_MODE_ALT_SCREEN_LEGACY (ghostty_mode_new(47, false)) /**< Alternate screen (legacy) */
72#define GHOSTTY_MODE_KEYPAD_KEYS (ghostty_mode_new(66, false)) /**< Application keypad */
73#define GHOSTTY_MODE_BACKARROW_KEY_MODE (ghostty_mode_new(67, false)) /**< Backarrow key mode (DECBKM) */
74#define GHOSTTY_MODE_LEFT_RIGHT_MARGIN (ghostty_mode_new(69, false)) /**< Left/right margin mode */
75#define GHOSTTY_MODE_NORMAL_MOUSE (ghostty_mode_new(1000, false)) /**< Normal mouse tracking */
76#define GHOSTTY_MODE_BUTTON_MOUSE (ghostty_mode_new(1002, false)) /**< Button-event mouse tracking */
77#define GHOSTTY_MODE_ANY_MOUSE (ghostty_mode_new(1003, false)) /**< Any-event mouse tracking */
78#define GHOSTTY_MODE_FOCUS_EVENT (ghostty_mode_new(1004, false)) /**< Focus in/out events */
79#define GHOSTTY_MODE_UTF8_MOUSE (ghostty_mode_new(1005, false)) /**< UTF-8 mouse format */
80#define GHOSTTY_MODE_SGR_MOUSE (ghostty_mode_new(1006, false)) /**< SGR mouse format */
81#define GHOSTTY_MODE_ALT_SCROLL (ghostty_mode_new(1007, false)) /**< Alternate scroll mode */
82#define GHOSTTY_MODE_URXVT_MOUSE (ghostty_mode_new(1015, false)) /**< URxvt mouse format */
83#define GHOSTTY_MODE_SGR_PIXELS_MOUSE (ghostty_mode_new(1016, false)) /**< SGR-Pixels mouse format */
84#define GHOSTTY_MODE_NUMLOCK_KEYPAD (ghostty_mode_new(1035, false)) /**< Ignore keypad with NumLock */
85#define GHOSTTY_MODE_ALT_ESC_PREFIX (ghostty_mode_new(1036, false)) /**< Alt key sends ESC prefix */
86#define GHOSTTY_MODE_ALT_SENDS_ESC (ghostty_mode_new(1039, false)) /**< Alt sends escape */
87#define GHOSTTY_MODE_REVERSE_WRAP_EXT (ghostty_mode_new(1045, false)) /**< Extended reverse wrap */
88#define GHOSTTY_MODE_ALT_SCREEN (ghostty_mode_new(1047, false)) /**< Alternate screen */
89#define GHOSTTY_MODE_SAVE_CURSOR (ghostty_mode_new(1048, false)) /**< Save cursor (DECSC) */
90#define GHOSTTY_MODE_ALT_SCREEN_SAVE (ghostty_mode_new(1049, false)) /**< Alt screen + save cursor + clear */
91#define GHOSTTY_MODE_BRACKETED_PASTE (ghostty_mode_new(2004, false)) /**< Bracketed paste mode */
92#define GHOSTTY_MODE_SYNC_OUTPUT (ghostty_mode_new(2026, false)) /**< Synchronized output */
93#define GHOSTTY_MODE_GRAPHEME_CLUSTER (ghostty_mode_new(2027, false)) /**< Grapheme cluster mode */
94#define GHOSTTY_MODE_COLOR_SCHEME_REPORT (ghostty_mode_new(2031, false)) /**< Report color scheme */
95#define GHOSTTY_MODE_IN_BAND_RESIZE (ghostty_mode_new(2048, false)) /**< In-band size reports */
96/** @} */
97
98/**
99 * A packed 16-bit terminal mode.
100 *
101 * Encodes a mode value (bits 0–14) and an ANSI flag (bit 15) into a
102 * single 16-bit integer. Use the inline helper functions to construct
103 * and inspect modes rather than manipulating bits directly.
104 */
105typedef uint16_t GhosttyMode;
106
107/**
108 * Create a mode from a mode value and ANSI flag.
109 *
110 * @param value The numeric mode value (0–32767)
111 * @param ansi true for an ANSI mode, false for a DEC private mode
112 * @return The packed mode
113 *
114 * @ingroup modes
115 */
116static inline GhosttyMode ghostty_mode_new(uint16_t value, bool ansi) {
117 return (GhosttyMode)((value & 0x7FFF) | ((uint16_t)ansi << 15));
118}
119
120/**
121 * Extract the numeric mode value from a mode.
122 *
123 * @param mode The mode
124 * @return The mode value (0–32767)
125 *
126 * @ingroup modes
127 */
128static inline uint16_t ghostty_mode_value(GhosttyMode mode) {
129 return mode & 0x7FFF;
130}
131
132/**
133 * Check whether a mode represents an ANSI mode.
134 *
135 * @param mode The mode
136 * @return true if this is an ANSI mode, false if it is a DEC private mode
137 *
138 * @ingroup modes
139 */
140static inline bool ghostty_mode_ansi(GhosttyMode mode) {
141 return (mode >> 15) != 0;
142}
143
144/**
145 * DECRPM report state values.
146 *
147 * These correspond to the Ps2 parameter in a DECRPM response
148 * sequence (CSI ? Ps1 ; Ps2 $ y).
149 */
150typedef enum GHOSTTY_ENUM_TYPED {
151 /** Mode is not recognized */
152 GHOSTTY_MODE_REPORT_NOT_RECOGNIZED = 0,
153 /** Mode is set (enabled) */
154 GHOSTTY_MODE_REPORT_SET = 1,
155 /** Mode is reset (disabled) */
156 GHOSTTY_MODE_REPORT_RESET = 2,
157 /** Mode is permanently set */
158 GHOSTTY_MODE_REPORT_PERMANENTLY_SET = 3,
159 /** Mode is permanently reset */
160 GHOSTTY_MODE_REPORT_PERMANENTLY_RESET = 4,
161 GHOSTTY_MODE_REPORT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
162} GhosttyModeReportState;
163
164/**
165 * Encode a DECRPM (DEC Private Mode Report) response sequence.
166 *
167 * Writes a mode report escape sequence into the provided buffer.
168 * The generated sequence has the form:
169 * - DEC private mode: CSI ? Ps1 ; Ps2 $ y
170 * - ANSI mode: CSI Ps1 ; Ps2 $ y
171 *
172 * If the buffer is too small, the function returns GHOSTTY_OUT_OF_SPACE
173 * and writes the required buffer size to @p out_written. The caller can
174 * then retry with a sufficiently sized buffer.
175 *
176 * @param mode The mode identifying the mode to report on
177 * @param state The report state for this mode
178 * @param buf Output buffer to write the encoded sequence into (may be NULL)
179 * @param buf_len Size of the output buffer in bytes
180 * @param[out] out_written On success, the number of bytes written. On
181 * GHOSTTY_OUT_OF_SPACE, the required buffer size.
182 * @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE if the buffer
183 * is too small
184 */
185GHOSTTY_API GhosttyResult ghostty_mode_report_encode(
186 GhosttyMode mode,
187 GhosttyModeReportState state,
188 char* buf,
189 size_t buf_len,
190 size_t* out_written);
191
192#ifdef __cplusplus
193}
194#endif
195
196/** @} */
197
198#endif /* GHOSTTY_VT_MODES_H */