vt100/
term.rs

1// TODO: read all of this from terminfo
2
3pub trait BufWrite {
4    fn write_buf(&self, buf: &mut Vec<u8>);
5}
6
7#[derive(Default, Debug)]
8#[must_use = "this struct does nothing unless you call write_buf"]
9pub struct ClearScreen;
10
11impl BufWrite for ClearScreen {
12    fn write_buf(&self, buf: &mut Vec<u8>) {
13        buf.extend_from_slice(b"\x1b[H\x1b[J");
14    }
15}
16
17#[derive(Default, Debug)]
18#[must_use = "this struct does nothing unless you call write_buf"]
19pub struct ClearRowForward;
20
21impl BufWrite for ClearRowForward {
22    fn write_buf(&self, buf: &mut Vec<u8>) {
23        buf.extend_from_slice(b"\x1b[K");
24    }
25}
26
27#[derive(Default, Debug)]
28#[must_use = "this struct does nothing unless you call write_buf"]
29pub struct Crlf;
30
31impl BufWrite for Crlf {
32    fn write_buf(&self, buf: &mut Vec<u8>) {
33        buf.extend_from_slice(b"\r\n");
34    }
35}
36
37#[derive(Default, Debug)]
38#[must_use = "this struct does nothing unless you call write_buf"]
39pub struct Backspace;
40
41impl BufWrite for Backspace {
42    fn write_buf(&self, buf: &mut Vec<u8>) {
43        buf.extend_from_slice(b"\x08");
44    }
45}
46
47#[derive(Default, Debug)]
48#[must_use = "this struct does nothing unless you call write_buf"]
49pub struct SaveCursor;
50
51impl BufWrite for SaveCursor {
52    fn write_buf(&self, buf: &mut Vec<u8>) {
53        buf.extend_from_slice(b"\x1b7");
54    }
55}
56
57#[derive(Default, Debug)]
58#[must_use = "this struct does nothing unless you call write_buf"]
59pub struct RestoreCursor;
60
61impl BufWrite for RestoreCursor {
62    fn write_buf(&self, buf: &mut Vec<u8>) {
63        buf.extend_from_slice(b"\x1b8");
64    }
65}
66
67#[derive(Default, Debug)]
68#[must_use = "this struct does nothing unless you call write_buf"]
69pub struct MoveTo {
70    row: u16,
71    col: u16,
72}
73
74impl MoveTo {
75    pub fn new(pos: crate::grid::Pos) -> Self {
76        Self {
77            row: pos.row,
78            col: pos.col,
79        }
80    }
81}
82
83impl BufWrite for MoveTo {
84    fn write_buf(&self, buf: &mut Vec<u8>) {
85        if self.row == 0 && self.col == 0 {
86            buf.extend_from_slice(b"\x1b[H");
87        } else {
88            buf.extend_from_slice(b"\x1b[");
89            extend_itoa(buf, self.row + 1);
90            buf.push(b';');
91            extend_itoa(buf, self.col + 1);
92            buf.push(b'H');
93        }
94    }
95}
96
97#[derive(Default, Debug)]
98#[must_use = "this struct does nothing unless you call write_buf"]
99pub struct ClearAttrs;
100
101impl BufWrite for ClearAttrs {
102    fn write_buf(&self, buf: &mut Vec<u8>) {
103        buf.extend_from_slice(b"\x1b[m");
104    }
105}
106
107#[derive(Default, Debug)]
108#[must_use = "this struct does nothing unless you call write_buf"]
109pub struct Attrs {
110    fgcolor: Option<crate::attrs::Color>,
111    bgcolor: Option<crate::attrs::Color>,
112    bold: Option<bool>,
113    italic: Option<bool>,
114    underline: Option<bool>,
115    inverse: Option<bool>,
116}
117
118impl Attrs {
119    pub fn fgcolor(mut self, fgcolor: crate::attrs::Color) -> Self {
120        self.fgcolor = Some(fgcolor);
121        self
122    }
123
124    pub fn bgcolor(mut self, bgcolor: crate::attrs::Color) -> Self {
125        self.bgcolor = Some(bgcolor);
126        self
127    }
128
129    pub fn bold(mut self, bold: bool) -> Self {
130        self.bold = Some(bold);
131        self
132    }
133
134    pub fn italic(mut self, italic: bool) -> Self {
135        self.italic = Some(italic);
136        self
137    }
138
139    pub fn underline(mut self, underline: bool) -> Self {
140        self.underline = Some(underline);
141        self
142    }
143
144    pub fn inverse(mut self, inverse: bool) -> Self {
145        self.inverse = Some(inverse);
146        self
147    }
148}
149
150impl BufWrite for Attrs {
151    #[allow(unused_assignments)]
152    #[allow(clippy::branches_sharing_code)]
153    fn write_buf(&self, buf: &mut Vec<u8>) {
154        if self.fgcolor.is_none()
155            && self.bgcolor.is_none()
156            && self.bold.is_none()
157            && self.italic.is_none()
158            && self.underline.is_none()
159            && self.inverse.is_none()
160        {
161            return;
162        }
163
164        buf.extend_from_slice(b"\x1b[");
165        let mut first = true;
166
167        macro_rules! write_param {
168            ($i:expr) => {
169                if first {
170                    first = false;
171                } else {
172                    buf.push(b';');
173                }
174                extend_itoa(buf, $i);
175            };
176        }
177
178        if let Some(fgcolor) = self.fgcolor {
179            match fgcolor {
180                crate::attrs::Color::Default => {
181                    write_param!(39);
182                }
183                crate::attrs::Color::Idx(i) => {
184                    if i < 8 {
185                        write_param!(i + 30);
186                    } else if i < 16 {
187                        write_param!(i + 82);
188                    } else {
189                        write_param!(38);
190                        write_param!(5);
191                        write_param!(i);
192                    }
193                }
194                crate::attrs::Color::Rgb(r, g, b) => {
195                    write_param!(38);
196                    write_param!(2);
197                    write_param!(r);
198                    write_param!(g);
199                    write_param!(b);
200                }
201            }
202        }
203
204        if let Some(bgcolor) = self.bgcolor {
205            match bgcolor {
206                crate::attrs::Color::Default => {
207                    write_param!(49);
208                }
209                crate::attrs::Color::Idx(i) => {
210                    if i < 8 {
211                        write_param!(i + 40);
212                    } else if i < 16 {
213                        write_param!(i + 92);
214                    } else {
215                        write_param!(48);
216                        write_param!(5);
217                        write_param!(i);
218                    }
219                }
220                crate::attrs::Color::Rgb(r, g, b) => {
221                    write_param!(48);
222                    write_param!(2);
223                    write_param!(r);
224                    write_param!(g);
225                    write_param!(b);
226                }
227            }
228        }
229
230        if let Some(bold) = self.bold {
231            if bold {
232                write_param!(1);
233            } else {
234                write_param!(22);
235            }
236        }
237
238        if let Some(italic) = self.italic {
239            if italic {
240                write_param!(3);
241            } else {
242                write_param!(23);
243            }
244        }
245
246        if let Some(underline) = self.underline {
247            if underline {
248                write_param!(4);
249            } else {
250                write_param!(24);
251            }
252        }
253
254        if let Some(inverse) = self.inverse {
255            if inverse {
256                write_param!(7);
257            } else {
258                write_param!(27);
259            }
260        }
261
262        buf.push(b'm');
263    }
264}
265
266#[derive(Debug)]
267#[must_use = "this struct does nothing unless you call write_buf"]
268pub struct MoveRight {
269    count: u16,
270}
271
272impl MoveRight {
273    pub fn new(count: u16) -> Self {
274        Self { count }
275    }
276}
277
278impl Default for MoveRight {
279    fn default() -> Self {
280        Self { count: 1 }
281    }
282}
283
284impl BufWrite for MoveRight {
285    fn write_buf(&self, buf: &mut Vec<u8>) {
286        match self.count {
287            0 => {}
288            1 => buf.extend_from_slice(b"\x1b[C"),
289            n => {
290                buf.extend_from_slice(b"\x1b[");
291                extend_itoa(buf, n);
292                buf.push(b'C');
293            }
294        }
295    }
296}
297
298#[derive(Debug)]
299#[must_use = "this struct does nothing unless you call write_buf"]
300pub struct EraseChar {
301    count: u16,
302}
303
304impl EraseChar {
305    pub fn new(count: u16) -> Self {
306        Self { count }
307    }
308}
309
310impl Default for EraseChar {
311    fn default() -> Self {
312        Self { count: 1 }
313    }
314}
315
316impl BufWrite for EraseChar {
317    fn write_buf(&self, buf: &mut Vec<u8>) {
318        match self.count {
319            0 => {}
320            1 => buf.extend_from_slice(b"\x1b[X"),
321            n => {
322                buf.extend_from_slice(b"\x1b[");
323                extend_itoa(buf, n);
324                buf.push(b'X');
325            }
326        }
327    }
328}
329
330#[derive(Default, Debug)]
331#[must_use = "this struct does nothing unless you call write_buf"]
332pub struct HideCursor {
333    state: bool,
334}
335
336impl HideCursor {
337    pub fn new(state: bool) -> Self {
338        Self { state }
339    }
340}
341
342impl BufWrite for HideCursor {
343    fn write_buf(&self, buf: &mut Vec<u8>) {
344        if self.state {
345            buf.extend_from_slice(b"\x1b[?25l");
346        } else {
347            buf.extend_from_slice(b"\x1b[?25h");
348        }
349    }
350}
351
352#[derive(Debug)]
353#[must_use = "this struct does nothing unless you call write_buf"]
354pub struct MoveFromTo {
355    from: crate::grid::Pos,
356    to: crate::grid::Pos,
357}
358
359impl MoveFromTo {
360    pub fn new(from: crate::grid::Pos, to: crate::grid::Pos) -> Self {
361        Self { from, to }
362    }
363}
364
365impl BufWrite for MoveFromTo {
366    fn write_buf(&self, buf: &mut Vec<u8>) {
367        if self.to.row == self.from.row + 1 && self.to.col == 0 {
368            crate::term::Crlf::default().write_buf(buf);
369        } else if self.from.row == self.to.row && self.from.col < self.to.col
370        {
371            crate::term::MoveRight::new(self.to.col - self.from.col)
372                .write_buf(buf);
373        } else if self.to != self.from {
374            crate::term::MoveTo::new(self.to).write_buf(buf);
375        }
376    }
377}
378
379#[derive(Default, Debug)]
380#[must_use = "this struct does nothing unless you call write_buf"]
381pub struct AudibleBell;
382
383impl BufWrite for AudibleBell {
384    fn write_buf(&self, buf: &mut Vec<u8>) {
385        buf.push(b'\x07');
386    }
387}
388
389#[derive(Default, Debug)]
390#[must_use = "this struct does nothing unless you call write_buf"]
391pub struct VisualBell;
392
393impl BufWrite for VisualBell {
394    fn write_buf(&self, buf: &mut Vec<u8>) {
395        buf.extend_from_slice(b"\x1bg");
396    }
397}
398
399#[must_use = "this struct does nothing unless you call write_buf"]
400pub struct ChangeTitle<'a> {
401    icon_name: &'a str,
402    title: &'a str,
403    prev_icon_name: &'a str,
404    prev_title: &'a str,
405}
406
407impl<'a> ChangeTitle<'a> {
408    pub fn new(
409        icon_name: &'a str,
410        title: &'a str,
411        prev_icon_name: &'a str,
412        prev_title: &'a str,
413    ) -> Self {
414        Self {
415            icon_name,
416            title,
417            prev_icon_name,
418            prev_title,
419        }
420    }
421}
422
423impl<'a> BufWrite for ChangeTitle<'a> {
424    fn write_buf(&self, buf: &mut Vec<u8>) {
425        if self.icon_name == self.title
426            && (self.icon_name != self.prev_icon_name
427                || self.title != self.prev_title)
428        {
429            buf.extend_from_slice(b"\x1b]0;");
430            buf.extend_from_slice(self.icon_name.as_bytes());
431            buf.push(b'\x07');
432        } else {
433            if self.icon_name != self.prev_icon_name {
434                buf.extend_from_slice(b"\x1b]1;");
435                buf.extend_from_slice(self.icon_name.as_bytes());
436                buf.push(b'\x07');
437            }
438            if self.title != self.prev_title {
439                buf.extend_from_slice(b"\x1b]2;");
440                buf.extend_from_slice(self.title.as_bytes());
441                buf.push(b'\x07');
442            }
443        }
444    }
445}
446
447#[derive(Default, Debug)]
448#[must_use = "this struct does nothing unless you call write_buf"]
449pub struct ApplicationKeypad {
450    state: bool,
451}
452
453impl ApplicationKeypad {
454    pub fn new(state: bool) -> Self {
455        Self { state }
456    }
457}
458
459impl BufWrite for ApplicationKeypad {
460    fn write_buf(&self, buf: &mut Vec<u8>) {
461        if self.state {
462            buf.extend_from_slice(b"\x1b=");
463        } else {
464            buf.extend_from_slice(b"\x1b>");
465        }
466    }
467}
468
469#[derive(Default, Debug)]
470#[must_use = "this struct does nothing unless you call write_buf"]
471pub struct ApplicationCursor {
472    state: bool,
473}
474
475impl ApplicationCursor {
476    pub fn new(state: bool) -> Self {
477        Self { state }
478    }
479}
480
481impl BufWrite for ApplicationCursor {
482    fn write_buf(&self, buf: &mut Vec<u8>) {
483        if self.state {
484            buf.extend_from_slice(b"\x1b[?1h");
485        } else {
486            buf.extend_from_slice(b"\x1b[?1l");
487        }
488    }
489}
490
491#[derive(Default, Debug)]
492#[must_use = "this struct does nothing unless you call write_buf"]
493pub struct BracketedPaste {
494    state: bool,
495}
496
497impl BracketedPaste {
498    pub fn new(state: bool) -> Self {
499        Self { state }
500    }
501}
502
503impl BufWrite for BracketedPaste {
504    fn write_buf(&self, buf: &mut Vec<u8>) {
505        if self.state {
506            buf.extend_from_slice(b"\x1b[?2004h");
507        } else {
508            buf.extend_from_slice(b"\x1b[?2004l");
509        }
510    }
511}
512
513#[derive(Default, Debug)]
514#[must_use = "this struct does nothing unless you call write_buf"]
515pub struct MouseProtocolMode {
516    mode: crate::screen::MouseProtocolMode,
517    prev: crate::screen::MouseProtocolMode,
518}
519
520impl MouseProtocolMode {
521    pub fn new(
522        mode: crate::screen::MouseProtocolMode,
523        prev: crate::screen::MouseProtocolMode,
524    ) -> Self {
525        Self { mode, prev }
526    }
527}
528
529impl BufWrite for MouseProtocolMode {
530    fn write_buf(&self, buf: &mut Vec<u8>) {
531        if self.mode == self.prev {
532            return;
533        }
534
535        match self.mode {
536            crate::screen::MouseProtocolMode::None => match self.prev {
537                crate::screen::MouseProtocolMode::None => {}
538                crate::screen::MouseProtocolMode::Press => {
539                    buf.extend_from_slice(b"\x1b[?9l");
540                }
541                crate::screen::MouseProtocolMode::PressRelease => {
542                    buf.extend_from_slice(b"\x1b[?1000l");
543                }
544                crate::screen::MouseProtocolMode::ButtonMotion => {
545                    buf.extend_from_slice(b"\x1b[?1002l");
546                }
547                crate::screen::MouseProtocolMode::AnyMotion => {
548                    buf.extend_from_slice(b"\x1b[?1003l");
549                }
550            },
551            crate::screen::MouseProtocolMode::Press => {
552                buf.extend_from_slice(b"\x1b[?9h");
553            }
554            crate::screen::MouseProtocolMode::PressRelease => {
555                buf.extend_from_slice(b"\x1b[?1000h");
556            }
557            crate::screen::MouseProtocolMode::ButtonMotion => {
558                buf.extend_from_slice(b"\x1b[?1002h");
559            }
560            crate::screen::MouseProtocolMode::AnyMotion => {
561                buf.extend_from_slice(b"\x1b[?1003h");
562            }
563        }
564    }
565}
566
567#[derive(Default, Debug)]
568#[must_use = "this struct does nothing unless you call write_buf"]
569pub struct MouseProtocolEncoding {
570    encoding: crate::screen::MouseProtocolEncoding,
571    prev: crate::screen::MouseProtocolEncoding,
572}
573
574impl MouseProtocolEncoding {
575    pub fn new(
576        encoding: crate::screen::MouseProtocolEncoding,
577        prev: crate::screen::MouseProtocolEncoding,
578    ) -> Self {
579        Self { encoding, prev }
580    }
581}
582
583impl BufWrite for MouseProtocolEncoding {
584    fn write_buf(&self, buf: &mut Vec<u8>) {
585        if self.encoding == self.prev {
586            return;
587        }
588
589        match self.encoding {
590            crate::screen::MouseProtocolEncoding::Default => {
591                match self.prev {
592                    crate::screen::MouseProtocolEncoding::Default => {}
593                    crate::screen::MouseProtocolEncoding::Utf8 => {
594                        buf.extend_from_slice(b"\x1b[?1005l");
595                    }
596                    crate::screen::MouseProtocolEncoding::Sgr => {
597                        buf.extend_from_slice(b"\x1b[?1006l");
598                    }
599                }
600            }
601            crate::screen::MouseProtocolEncoding::Utf8 => {
602                buf.extend_from_slice(b"\x1b[?1005h");
603            }
604            crate::screen::MouseProtocolEncoding::Sgr => {
605                buf.extend_from_slice(b"\x1b[?1006h");
606            }
607        }
608    }
609}
610
611fn extend_itoa<I: itoa::Integer>(buf: &mut Vec<u8>, i: I) {
612    let mut itoa_buf = itoa::Buffer::new();
613    buf.extend_from_slice(itoa_buf.format(i).as_bytes());
614}