termal_core/
codes.rs

1//! Module with ansi escape codes.
2//!
3//! Most of them are taken from:
4//! <https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797>
5//!
6//! There are several types of codes here:
7//! - **Sequences:** string/char used to introduce escape sequence, most of the
8//!   other codes use them
9//! - **General ascii codes:** single char sequences some of them have escape
10//!   codes in rust string/char literals (such as '\n')
11//! - **Macro codes:** these escape codes have one or more parameters. Here
12//!   they are in form of a macro that takes the parameters. If the macro is
13//!   invoked with literals, it expands to `&'static str`. If the arguments
14//!   are not literals it expands to a call to the `format!` macro. Because
15//!   these codes may expand either to `&'static str` or `String` you can use
16//!   the [`GetString::get_string`] method to get `String`, or you can use
17//!   `AsRef<str>::as_ref` method to get `&str`, or you can use
18//!   `Into<Cow<'static, str>>::into` to get the possibly owned string.
19//! - **String codes:** these codes are just strings that can be just printed
20//!   to terminal to do what they say they do. This is the majority of the
21//!   codes.
22
23use std::fmt::Display;
24
25use base64::Engine;
26use place_macro::place;
27
28/// Creates the given sequence, this is used internally, you should use
29/// the macro [`csi`]
30#[macro_export]
31macro_rules! seq {
32    ($sq:literal, $i:literal) => {
33        concat!($sq, $i)
34    };
35    ($sq:literal, $i:literal, $f:literal, $($a:literal),*) => {
36        concat!($sq, $f $(, ';', $a)*, $i)
37    };
38    ($sq:literal, $i:literal, $f:expr $(,$a:expr)*) => {
39        $crate::seq!($sq, $i, $f, $(";{}"; $a),*)
40    };
41    ($sq:literal, $i:literal, $f:expr, $($l:literal; $e:expr),*) => {
42        format!(concat!($sq, "{}" $(,$l)*, $i), $f $(,$e)*)
43    }
44}
45
46// Sequences:
47
48/// The escape character
49pub const ESC: char = '\x1b';
50/// Control Sequence Introducer: Start of CSI sequence
51pub const CSI: &str = "\x1b[";
52/// Device Control String: Start of DCS sequence
53pub const DCS: &str = "\x1bP";
54/// Operating System Command: Start of OSC sequence
55pub const OSC: &str = "\x1b]";
56/// String terminator. Terminates for example DCS.
57pub const ST: &str = "\x1b\\";
58/// Single shift three
59pub const SS3: &str = "\x1bO";
60
61/// Creates control escape sequence, the first literal is the end of the
62/// sequence, the other arguments are the values in the sequence
63#[macro_export]
64macro_rules! csi {
65    ($i:literal $(,$a:expr)* $(,)?) => {
66        $crate::seq!("\x1b[", $i $(, $a)*)
67    };
68}
69
70/// Creates control escape sequence for graphic mode.
71#[macro_export]
72macro_rules! graphic {
73    ($($a:expr),* $(,)?) => {
74        $crate::csi!('m' $(, $a)*)
75    };
76}
77
78/// Creates operating system command sequence. The arguments are the values in
79/// the sequence.
80#[macro_export]
81macro_rules! osc {
82    ($($a:expr),+) => {
83        $crate::seq!("\x1b]", "\x1b\\", $($a),+)
84    };
85}
86
87/// Enables the given private terminal mode.
88#[macro_export]
89macro_rules! enable {
90    ($a:expr) => {
91        $crate::seq!("\x1b[?", 'h', $a)
92    };
93}
94
95/// Disables the given private terminal mode.
96#[macro_export]
97macro_rules! disable {
98    ($a:expr) => {
99        $crate::seq!("\x1b[?", 'l', $a)
100    };
101}
102
103// General ASCII codes
104
105/// Produces terminal bell
106pub const BELL: char = '\x07';
107/// Moves the cursor left by one positoin
108pub const BACKSPACE: char = '\x08';
109/// Horizontal tabulator, moves cursor to the next stop
110pub const HTAB: char = '\t';
111/// Moves the cursor to the start of the next line
112pub const NEWLINE: char = '\n';
113/// Vertical tabulator, moves the cursor to the next vertical stop
114pub const VTAB: char = '\x0b';
115/// Indicates new page, usualy has no use in terminal
116pub const FORMFEED: char = '\x0c';
117/// Moves cursor to the start of the line
118pub const CARRIAGE_RETURN: char = '\r';
119/// Does nothing
120pub const DELETE: char = '\x7f';
121
122// Cursor controls
123
124// For the macros is true that:
125// If you use literals it returns `&str`,
126// if you use expressions, it returns [`String`]. You can use the
127// `.get_string()` method from the trait [`GetString`] to get [`String`] in
128// both cases
129
130macro_rules! code_macro {
131    ($code:ident $(
132        $name:ident
133        $(, $($nam:ident)? $($lit:literal)?)+ ;
134        $($i:literal)? $(?$doc:literal)?),+ $(,)?
135    ) => {
136        place! {$(
137            $(#[doc = __repnl__($doc, " ")])?
138            #[macro_export]
139            macro_rules! $name {
140                (__start__($($(__s__ $nam:expr,)?)+) __s__ (,)?) => {
141                    __s__ crate::$code!($($i,)? $($(__s__ $nam)? $($lit)?),+)
142                }
143            }
144            pub use $name;
145        )+}
146    };
147    ($code:ident != $ex:literal => $(
148        $name:ident,
149        $nam:ident;
150        $($i:literal)? $(?$doc:literal)?),+ $(,)?
151    ) => {
152        place! {$(
153            $(#[doc = __repnl__($doc, " ")])?
154            #[macro_export]
155            macro_rules! $name {
156                (__start__(__s__ $nam:expr,)) => {{
157                    let v = __s__ $nam;
158                    if v == $ex {
159                        "".into()
160                    } else {
161                        __s__ crate::$code!($($i,)? v)
162                    }
163                }}
164            }
165            pub use $name;
166        )+}
167    };
168}
169
170/// Moves cursor to the given position.
171#[macro_export]
172macro_rules! move_to {
173    ($x:expr, $y:expr) => {
174        $crate::csi!('H', $y, $x)
175    };
176}
177
178pub use move_to;
179
180use crate::Rgb;
181
182code_macro!(csi != 0 =>
183    move_up, n; 'A' ? "Moves cursor up by N positions",
184    move_down, n; 'B' ? "Moves cursor down by N positions",
185    move_right, n; 'C' ? "Moves cursor right by N positions",
186    move_left, n; 'D' ? "Moves cursor left by N positions",
187    insert_lines, n; 'L' ? "Insert n lines at the cursor moving them down.",
188    delete_lines, n; 'M'
189        ? "Delete n lines at the cursor, moving the remaining from bottom.",
190    insert_chars, n; '@' ? "Insert n characters, moving them to the right.",
191    delete_chars, n; 'P' ? "Delete n characters, moving the chars from right.",
192    insert_columns, n; "'}}" ? "Insert n columns, moving them to the right.",
193    delete_columns, n; "'~" ? "Delete n columns, moving them from the right",
194    set_down, n; 'E' ? "Moves cursor to the start of line N lines down",
195    set_up, n; 'F' ? "Moves cursor to the start of line N lines up",
196    repeat_char, n; 'b' ? "Repeat the previous char n times."
197);
198
199code_macro!(csi
200    column, n; 'G' ? "Moves cursor to the given column",
201);
202
203/// Moves cursor one line up, scrolling if needed
204pub const UP_SCRL: &str = "\x1bM";
205/// Saves the cursor position (this is single save slot, not stack)
206pub const CUR_SAVE: &str = "\x1b7";
207/// Restores the cursor position to the last saved position (this is single
208/// save slot, not stack)
209pub const CUR_LOAD: &str = "\x1b8";
210
211// Erase codes
212
213/// Erases from the cursor to the end of the screen
214pub const ERASE_TO_END: &str = csi!('J');
215/// Erases from the start of the screen to the cursor
216pub const ERASE_FROM_START: &str = csi!('J', 1);
217/// Erases the entire screen
218pub const ERASE_SCREEN: &str = csi!('J', 2);
219/// Erases the whole screen and the scrollback buffer
220pub const ERASE_ALL: &str = csi!('J', 3);
221/// Erases from cursor to the end of the line
222pub const ERASE_TO_LN_END: &str = csi!('K');
223/// Erases from the start of the line to the cursor
224pub const ERASE_FROM_LN_START: &str = csi!('K', 1);
225/// Erases the entire line
226pub const ERASE_LINE: &str = csi!('K', 2);
227
228// Text modes
229
230/// Resets all the text modes (colors and styles)
231pub const RESET: &str = graphic!(0);
232
233/// Set bold text mode (on some terminals may be just brighter color)
234pub const BOLD: &str = graphic!(1);
235/// Set dim/faint text mode
236pub const FAINT: &str = graphic!(2);
237/// Set italic mode
238pub const ITALIC: &str = graphic!(3);
239/// Set underline mode
240pub const UNDERLINE: &str = graphic!(4);
241/// Set blinking mode
242pub const BLINKING: &str = graphic!(5);
243/// Set inverse mode (inverse foreground and background)
244pub const INVERSE: &str = graphic!(7);
245/// Set invisible mode (foreground is same as background)
246pub const INVISIBLE: &str = graphic!(8);
247/// Set striketrough mode
248pub const STRIKETROUGH: &str = graphic!(9);
249/// Set double underline mode
250pub const DOUBLE_UNDERLINE: &str = graphic!(21);
251/// Set ouverline mode
252pub const OVERLINE: &str = graphic!(53);
253
254/// Reset [`BOLD`] and [`FAINT`] mode
255pub const RESET_BOLD: &str = graphic!(22);
256/// Reset [`ITALIC`] mode
257pub const RESET_ITALIC: &str = graphic!(23);
258/// Reset [`UNDERLINE`] and [`DOUBLE_UNDERLINE`] mode
259pub const RESET_UNDERLINE: &str = graphic!(24);
260/// Reset [`BLINKING`] mode
261pub const RESET_BLINKING: &str = graphic!(25);
262/// Reset [`INVERSE`] mode
263pub const RESET_INVERSE: &str = graphic!(27);
264/// Reset [`INVISIBLE`] mode
265pub const RESET_INVISIBLE: &str = graphic!(28);
266/// Reset [`STRIKETROUGH`] mode
267pub const RESET_STRIKETROUGH: &str = graphic!(29);
268/// Reset [`OVERLINE`] mode.
269pub const RESET_OVERLINE: &str = graphic!(55);
270
271/// Set the foreground color to black (dark black)
272pub const BLACK_FG: &str = graphic!(30);
273/// Set the foreground color to white (bright white)
274pub const WHITE_FG: &str = graphic!(97);
275/// Set the foreground color to gray (bright black)
276pub const GRAY_FG: &str = graphic!(90);
277/// Set to foreground color to bright gray (dark white)
278pub const GRAY_BRIGHT_FG: &str = graphic!(37);
279
280/// Set the foreground color to red (bright red)
281pub const RED_FG: &str = graphic!(91);
282/// Set the foreground color to green (bright green)
283pub const GREEN_FG: &str = graphic!(92);
284/// Set the foreground color to yellow (bright yellow)
285pub const YELLOW_FG: &str = graphic!(93);
286/// Set the foreground color to blue (bright blue)
287pub const BLUE_FG: &str = graphic!(94);
288/// Set the foreground color to magenta (bright magenta)
289pub const MAGENTA_FG: &str = graphic!(95);
290/// Set the foreground color to cyan (bright cyan)
291pub const CYAN_FG: &str = graphic!(96);
292
293/// Set the foreground color to dark red
294pub const RED_DARK_FG: &str = graphic!(31);
295/// Set the foreground color to dark green
296pub const GREEN_DARK_FG: &str = graphic!(32);
297/// Set the foreground color to dark yellow
298pub const YELLOW_DARK_FG: &str = graphic!(33);
299/// Set the foreground color to dark blue
300pub const BLUE_DARK_FG: &str = graphic!(34);
301/// Set the foreground color to dark magenta
302pub const MAGENTA_DARK_FG: &str = graphic!(35);
303/// Set the foreground color to dark cyan
304pub const CYAN_DARK_FG: &str = graphic!(36);
305
306/// Reset the foreground color
307pub const RESET_FG: &str = graphic!(39);
308
309/// Set the background color to black (dark black)
310pub const BLACK_BG: &str = graphic!(40);
311/// Set the background color to white (bright white)
312pub const WHITE_BG: &str = graphic!(107);
313/// Set the background color to gray (bright black)
314pub const GRAY_BG: &str = graphic!(100);
315/// Set to background color to bright gray (dark white)
316pub const GRAY_BRIGHT_BG: &str = graphic!(47);
317
318/// Set the background color to red (bright red)
319pub const RED_BG: &str = graphic!(101);
320/// Set the background color to green (bright green)
321pub const GREEN_BG: &str = graphic!(102);
322/// Set the background color to yellow (bright yellow)
323pub const YELLOW_BG: &str = graphic!(103);
324/// Set the background color to blue (bright blue)
325pub const BLUE_BG: &str = graphic!(104);
326/// Set the background color to magenta (bright magenta)
327pub const MAGENTA_BG: &str = graphic!(105);
328/// Set the background color to cyan (bright cyan)
329pub const CYAN_BG: &str = graphic!(106);
330
331/// Set the background color to dark red
332pub const RED_DARK_BG: &str = graphic!(41);
333/// Set the background color to dark green
334pub const GREEN_DARK_BG: &str = graphic!(42);
335/// Set the background color to dark yellow
336pub const YELLOW_DARK_BG: &str = graphic!(43);
337/// Set the background color to dark blue
338pub const BLUE_DARK_BG: &str = graphic!(44);
339/// Set the background color to dark magenta
340pub const MAGENTA_DARK_BG: &str = graphic!(45);
341/// Set the background color to dark cyan
342pub const CYAN_DARK_BG: &str = graphic!(46);
343
344/// Reset the background color
345pub const RESET_BG: &str = graphic!(49);
346
347code_macro! { graphic
348    fg256, 38, 5, c;
349        ? "creates a foreground color, color is value in range 0..256",
350
351    bg256, 48, 5, c;
352        ? "creates a background color, color is value in range 0..256",
353
354    underline256, 58, 5, c;
355        ? "Set underline color as 256 color.",
356
357    fg, 38, 2, r, g, b;
358        ? "creates a true rgb foreground color. R, G and B must be values in
359           range 0..256",
360
361    bg, 48, 2, r, g, b;
362        ? "creates a true rgb background color. R, G and B must be values in
363           range 0..256",
364
365    underline_rgb, 58, 2, r, g, b;
366        ? "Set underline color as rgb.",
367}
368
369/// Reset the underline color.
370pub const RESET_UNDERLINE_COLOR: &str = graphic!(59);
371
372// Line modes
373/// Makes this line characters twice as large overlapping with the line below.
374pub const DOUBLE_CHAR_HEIGHT_DOWN: &str = "\x1b#3";
375/// Makes this line characters twice as large overlapping with the line above.
376pub const DOUBLE_CHAR_HEIGHT_UP: &str = "\x1b#4";
377/// Makes this line character twice as wide (but not twice as tall).
378pub const DOUBLE_CHAR_WIDTH: &str = "\x1b#6";
379/// Resets this line character size.
380pub const RESET_CHAR_SIZE: &str = "\x1b#5";
381
382// Screen modes
383
384/// Enables line wrapping
385pub const ENABLE_LINE_WRAP: &str = "\x1b[=7h";
386/// Disables line wrapping
387pub const DISABLE_LINE_WRAP: &str = "\x1b[=7l";
388
389/// Enables reverse color for the whole terminal display.
390pub const ENABLE_REVERSE_COLOR: &str = enable!(5);
391/// Disables reverse color for the whole terminal display. (This actually often
392/// doesn't work)
393pub const DISABLE_REVERSE_COLOR: &str = disable!(5);
394
395// Private modes
396
397/// Makes the cursor invisible
398pub const HIDE_CURSOR: &str = disable!(25);
399/// Makes the cursor visible
400pub const SHOW_CURSOR: &str = enable!(25);
401/// Saves the visible part of the screen buffer
402pub const SAVE_SCREEN: &str = disable!(47);
403/// Loads the last saved screen
404pub const LOAD_SCREEN: &str = enable!(47);
405/// Enables alternative buffer
406pub const ENABLE_ALTERNATIVE_BUFFER: &str = enable!(1049);
407/// Disables the laternative buffer
408pub const DISABLE_ALTERNATIVE_BUFFER: &str = disable!(1049);
409
410// Other
411/// Full terminal reset. Clear the screen, buffer, reset all modes, ...
412pub const FULL_RESET: &str = "\x1bc";
413
414/// Request the device attributes.
415pub const REQUEST_DEVICE_ATTRIBUTES: &str = csi!('c');
416/// Request the device status.
417pub const REQUEST_STATUS_REPORT: &str = csi!('n', 5);
418/// Request the current cursor position. In some terminals, the report may be
419/// ambigous with F3 key press with modifiers.
420pub const REQUEST_CURSOR_POSITION: &str = csi!('n', 6);
421/// Request the current cursor position. Difference from
422/// [`REQUEST_CURSOR_POSITION`] is that the response is not ambigous, but it is
423/// not supported by some terminals that support [`REQUEST_CURSOR_POSITION`].
424pub const REQUEST_CURSOR_POSITION2: &str = "\x1b[?6n";
425/// Requests the terminal name and version.
426pub const REQUEST_TERMINAL_NAME: &str = "\x1b[>0q";
427/// Request the text area size of terminal in pixels.
428pub const REQUEST_TEXT_AREA_SIZE_PX: &str = csi!('t', 14);
429/// Request size of single character on creen in pixels.
430pub const REQUEST_CHAR_SIZE: &str = csi!('t', 16);
431/// Request size of the text area in characters.
432pub const REQUEST_TEXT_AREA_SIZE: &str = csi!('t', 18);
433/// Request the number of sixel color registers.
434pub const REQUEST_SIXEL_COLORS: &str = "\x1b[?1;1;1S";
435
436/// Enables mouse tracking for X and Y coordinate on press.
437pub const ENABLE_MOUSE_XY_TRACKING: &str = enable!(9);
438/// Disables mouse tracking for X and Y coordinate on press.
439pub const DISABLE_MOUSE_XY_TRACKING: &str = disable!(9);
440/// Enables mouse tracking for X and Y coordinate on press and release.
441pub const ENABLE_MOUSE_XY_PR_TRACKING: &str = enable!(1000);
442/// Disables mouse tracking for X and Y coordinate on press and release.
443pub const DISABLE_MOUSE_XY_PR_TRACKING: &str = disable!(1000);
444/// Enables mouse tracking for X and Y coordinate on press, release and drag.
445pub const ENABLE_MOUSE_XY_DRAG_TRACKING: &str = enable!(1002);
446/// Disables mouse tracking for X and Y coordinate on press, release and drag.
447pub const DISABLE_MOUSE_XY_DRAG_TRACKING: &str = disable!(1002);
448/// Enables mouse tracking for X and Y coordinate on press, release, drag and
449/// move.
450pub const ENABLE_MOUSE_XY_ALL_TRACKING: &str = enable!(1003);
451/// Disables mouse tracking for X and Y coordinate on press, release, drag and
452/// move.
453pub const DISABLE_MOUSE_XY_ALL_TRACKING: &str = disable!(1003);
454/// Enables sending event on focus gain.
455pub const ENABLE_FOCUS_EVENT: &str = enable!(1004);
456/// Disables sending event on focus gain.
457pub const DISABLE_FOCUS_EVENT: &str = disable!(1004);
458/// Enables extension to send mouse inputs in format extended to utf8 two byte
459/// characters.
460pub const ENABLE_MOUSE_XY_UTF8_EXT: &str = enable!(1005);
461/// Disables extension to send mouse inputs in format extended to utf8 two byte
462/// characters.
463pub const DISABLE_MOUSE_XY_UTF8_EXT: &str = disable!(1005);
464/// Enables extension to send mouse inputs in different format as position in
465/// characters.
466pub const ENABLE_MOUSE_XY_EXT: &str = enable!(1006);
467/// Disables extension to send mouse inputs in different format as position in
468/// characters.
469pub const DISABLE_MOUSE_XY_EXT: &str = disable!(1006);
470/// Enables URXVT mouse extension. Not recommended, rather use
471/// [`ENABLE_MOUSE_XY_EXT`].
472pub const ENABLE_MOUSE_XY_URXVT_EXT: &str = enable!(1015);
473/// Disables URXVT mouse extension.
474pub const DISABLE_MOUSE_XY_URXVT_EXT: &str = disable!(1015);
475/// Enables extension to send mouse inputs in different format as position in
476/// pixels.
477pub const ENABLE_MOUSE_XY_PIX_EXT: &str = enable!(1016);
478/// Disables extension to send mouse inputs in different format as position in
479/// pixels.
480pub const DISABLE_MOUSE_XY_PIX_EXT: &str = disable!(1016);
481
482code_macro! { csi
483    scroll_region, t, b; 'r'
484        ? "Set the scroll region in the terminal. Also moves the cursor to the
485           top left."
486}
487
488/// Reset the scroll region
489pub const RESET_SCROLL_REGION: &str = scroll_region!(0, 0);
490/// Don't limit the printing area.
491pub const DONT_LIMIT_PRINT_TO_SCROLL_REGION: &str = enable!(19);
492/// Limit printing area only to scroll region.
493pub const LIMIT_PRINT_TO_SCROLL_REGION: &str = disable!(19);
494
495/// Enables bracketed paste mode. In this mode, pasted text is treated
496/// verbatim.
497pub const ENABLE_BRACKETED_PASTE_MODE: &str = enable!(2004);
498pub const DISABLE_BRACKETED_PASTE_MODE: &str = disable!(2004);
499
500#[derive(Clone, Debug, Copy, Eq, PartialEq)]
501pub enum CursorStyle {
502    /// Set cursor to block.
503    /// - `true` -> blink
504    /// - `false` -> don't blink
505    /// - [`None`] -> blink (default)
506    Block(Option<bool>),
507    /// Set cursor to underline.
508    /// - `true` -> blink
509    /// - `false` -> don't blink
510    Underline(bool),
511    /// Set cursor vertical bar.
512    /// - `true` -> blink
513    /// - `false` -> don't blink
514    Bar(bool),
515}
516
517pub fn set_cursor(style: CursorStyle) -> &'static str {
518    match style {
519        CursorStyle::Block(Some(true)) => csi!(" q", 0),
520        CursorStyle::Block(None) => csi!(" q", 1),
521        CursorStyle::Block(Some(false)) => csi!(" q", 2),
522        CursorStyle::Underline(true) => csi!(" q", 3),
523        CursorStyle::Underline(false) => csi!(" q", 4),
524        CursorStyle::Bar(true) => csi!(" q", 5),
525        CursorStyle::Bar(false) => csi!(" q", 6),
526    }
527}
528
529// OSC sequences
530
531code_macro! {osc
532    request_color_code, 4, code, "?";
533        ? "Requests the current color assigned to the given color code.",
534
535    reset_color_code, 104, code;
536        ? "Resets the color definition for the given color code.",
537}
538
539/// Defines color for the given color code.
540pub fn define_color_code<T>(code: u8, color: impl Into<Rgb<T>>) -> String
541where
542    Rgb<T>: Display,
543{
544    osc!(4, code, color.into())
545}
546
547/// Sets the default foreground color
548pub fn set_default_fg_color<T>(color: impl Into<Rgb<T>>) -> String
549where
550    Rgb<T>: Display,
551{
552    osc!(10, color.into())
553}
554
555/// Sets the default foreground color
556pub fn set_default_bg_color<T>(color: impl Into<Rgb<T>>) -> String
557where
558    Rgb<T>: Display,
559{
560    osc!(11, color.into())
561}
562
563/// Sets the color of the cursor.
564pub fn set_cursor_color<T>(color: impl Into<Rgb<T>>) -> String
565where
566    Rgb<T>: Display,
567{
568    osc!(12, color.into())
569}
570
571/// Resets all the color codes to their default colors.
572pub const RESET_ALL_COLOR_CODES: &str = osc!(104);
573/// Resets the default foreground color.
574pub const RESET_DEFAULT_FG_COLOR: &str = osc!(110);
575/// Resets the default background color.
576pub const RESET_DEFAULT_BG_COLOR: &str = osc!(111);
577/// Resets the cursor color.
578pub const RESET_CURSOR_COLOR: &str = osc!(112);
579
580/// Requests the default foreground color.
581pub const REQUEST_DEFAULT_FG_COLOR: &str = osc!(10, '?');
582/// Requests the default background color.
583pub const REQUEST_DEFAULT_BG_COLOR: &str = osc!(11, '?');
584/// Requests the cursor color.
585pub const REQUEST_CURSOR_COLOR: &str = osc!(12, '?');
586
587/// Requests the copy/paste selection data.
588pub const REQUEST_SELECTION: &str = osc!(52, "", '?');
589
590/// Specifies the selection buffer.
591#[derive(Clone, Debug, Copy, Eq, PartialEq)]
592pub enum Selection {
593    Clipboard,
594    Primary,
595    Secondary,
596    // Either [`Primary`] or [`Clipboard`] (what is the configured default)
597    Select,
598    Cut0,
599    Cut1,
600    Cut2,
601    Cut3,
602    Cut4,
603    Cut5,
604    Cut6,
605    Cut7,
606}
607
608impl Selection {
609    fn get_char(&self) -> char {
610        match self {
611            Selection::Clipboard => 'c',
612            Selection::Primary => 'p',
613            Selection::Secondary => 'q',
614            Selection::Select => 's',
615            Selection::Cut0 => '0',
616            Selection::Cut1 => '1',
617            Selection::Cut2 => '2',
618            Selection::Cut3 => '3',
619            Selection::Cut4 => '4',
620            Selection::Cut5 => '5',
621            Selection::Cut6 => '6',
622            Selection::Cut7 => '7',
623        }
624    }
625}
626
627fn prepare_selection(sel: impl IntoIterator<Item = Selection>) -> String {
628    let mut res = "\x1b]52;".to_string();
629    for b in sel {
630        res.push(b.get_char());
631    }
632    res.push(';');
633    res
634}
635
636/// Requests selection for the first available of the given selection buffers.
637/// If empty requests the default buffer selection.
638pub fn request_selectoin(sel: impl IntoIterator<Item = Selection>) -> String {
639    prepare_selection(sel) + "?\x1b\\"
640}
641
642/// Sets the given selection buffers. If empty sets the default selection
643/// buffers.
644pub fn set_selection(
645    sel: impl IntoIterator<Item = Selection>,
646    data: impl AsRef<[u8]>,
647) -> String {
648    let mut res = prepare_selection(sel);
649    base64::prelude::BASE64_STANDARD.encode_string(data, &mut res);
650    res + "\x1b\\"
651}
652
653// TODO: Kitty extensions
654
655// Internal
656
657/// Input code for bracketed paste start. Used internally.
658pub const BRACKETED_PASTE_START: &str = "\x1b[200~";
659/// Input code for bracketed paste end. Used internally.
660pub const BRACKETED_PASTE_END: &str = "\x1b[201~";
661
662/// Trait for getting string from &str and String
663pub trait GetString {
664    /// If [`self`] is `&str` uses `.to_owned()`, if [`self`] is [`String`] returns
665    /// [`self`]
666    fn get_string(self) -> String;
667}
668
669impl GetString for &str {
670    fn get_string(self) -> String {
671        self.to_owned()
672    }
673}
674
675impl GetString for String {
676    fn get_string(self) -> String {
677        self
678    }
679}
680
681#[cfg(test)]
682mod tests {
683    use std::any::TypeId;
684
685    fn type_id_of<T: 'static>(_: T) -> TypeId {
686        TypeId::of::<T>()
687    }
688
689    #[test]
690    fn test_macros() {
691        assert_eq!(csi!('a', 1, 2, 3, 4, 5), "\x1b[1;2;3;4;5a");
692        assert_eq!(csi!('a', 1 + 0, 2, 3, 4, 5), "\x1b[1;2;3;4;5a");
693        assert_eq!(type_id_of(csi!('a', 1, 2, 3, 4, 5)), TypeId::of::<&str>());
694        assert_eq!(
695            type_id_of(csi!('a', 1 + 0, 2, 3, 4, 5)),
696            TypeId::of::<String>()
697        );
698    }
699}