Skip to main content

prototty_text/
wrap.rs

1use prototty_render::*;
2#[cfg(feature = "serialize")]
3use serde::{Deserialize, Serialize};
4
5pub trait Wrap: private_wrap::Sealed {
6    #[doc(hidden)]
7    fn clear(&mut self);
8    #[doc(hidden)]
9    fn process_character<F: Frame, C: ColModify>(
10        &mut self,
11        character: char,
12        style: Style,
13        context: ViewContext<C>,
14        frame: &mut F,
15    );
16    #[doc(hidden)]
17    fn flush<F: Frame, C: ColModify>(&mut self, context: ViewContext<C>, frame: &mut F) {
18        let _ = context;
19        let _ = frame;
20    }
21    #[doc(hidden)]
22    fn num_lines(&self) -> usize;
23}
24
25#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
26#[derive(Debug, Clone)]
27pub struct None {
28    cursor: Coord,
29}
30
31#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
32#[derive(Debug, Clone)]
33pub struct Word {
34    cursor: Coord,
35    current_word_buffer: Vec<ViewCell>,
36}
37
38#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
39#[derive(Debug, Clone)]
40pub struct Char {
41    cursor: Coord,
42}
43
44impl None {
45    pub fn new() -> Self {
46        Self {
47            cursor: Coord::new(0, 0),
48        }
49    }
50}
51
52impl Word {
53    pub fn new() -> Self {
54        Self {
55            cursor: Coord::new(0, 0),
56            current_word_buffer: Vec::new(),
57        }
58    }
59}
60
61impl Char {
62    pub fn new() -> Self {
63        Self {
64            cursor: Coord::new(0, 0),
65        }
66    }
67}
68
69impl Default for None {
70    fn default() -> Self {
71        Self::new()
72    }
73}
74
75impl Default for Word {
76    fn default() -> Self {
77        Self::new()
78    }
79}
80
81impl Default for Char {
82    fn default() -> Self {
83        Self::new()
84    }
85}
86
87impl Wrap for None {
88    fn clear(&mut self) {
89        self.cursor = Coord::new(0, 0);
90    }
91    fn process_character<F: Frame, C: ColModify>(
92        &mut self,
93        character: char,
94        style: Style,
95        context: ViewContext<C>,
96        frame: &mut F,
97    ) {
98        match character {
99            '\n' => {
100                self.cursor.x = 0;
101                self.cursor.y += 1;
102            }
103            '\r' => self.cursor.x = 0,
104            other => {
105                let view_cell = ViewCell {
106                    character: Some(other),
107                    style,
108                };
109                frame.set_cell_relative(self.cursor, 0, view_cell, context);
110                self.cursor += Coord::new(1, 0);
111            }
112        }
113    }
114    fn num_lines(&self) -> usize {
115        self.cursor.y as usize + 1
116    }
117}
118
119impl Wrap for Word {
120    fn clear(&mut self) {
121        self.cursor = Coord::new(0, 0);
122        self.current_word_buffer.clear();
123    }
124
125    fn process_character<F: Frame, C: ColModify>(
126        &mut self,
127        character: char,
128        style: Style,
129        context: ViewContext<C>,
130        frame: &mut F,
131    ) {
132        match character {
133            '\n' => {
134                self.flush(context, frame);
135                self.cursor.x = 0;
136                self.cursor.y += 1;
137            }
138            '\r' => {
139                self.flush(context, frame);
140                self.cursor.x = 0;
141            }
142            ' ' => {
143                self.flush(context, frame);
144                if self.cursor.x != 0 {
145                    let view_cell = ViewCell {
146                        character: Some(' '),
147                        style,
148                    };
149                    frame.set_cell_relative(self.cursor, 0, view_cell, context);
150                    self.cursor.x += 1;
151                    assert!(self.cursor.x as u32 <= context.size.width());
152                    if self.cursor.x as u32 == context.size.width() {
153                        self.cursor.x = 0;
154                        self.cursor.y += 1;
155                    }
156                }
157            }
158            other => {
159                let view_cell = ViewCell {
160                    character: Some(other),
161                    style,
162                };
163                self.current_word_buffer.push(view_cell);
164                assert!(self.cursor.x as u32 + self.current_word_buffer.len() as u32 <= context.size.width());
165                if self.cursor.x as u32 + self.current_word_buffer.len() as u32 == context.size.width() {
166                    if self.cursor.x == 0 {
167                        self.flush(context, frame);
168                    } else {
169                        self.cursor.x = 0;
170                        self.cursor.y += 1;
171                    }
172                }
173            }
174        }
175    }
176
177    fn flush<F: Frame, C: ColModify>(&mut self, context: ViewContext<C>, frame: &mut F) {
178        for view_cell in self.current_word_buffer.drain(..) {
179            frame.set_cell_relative(self.cursor, 0, view_cell, context);
180            self.cursor.x += 1;
181        }
182        assert!(self.cursor.x as u32 <= context.size.width());
183        if self.cursor.x as u32 == context.size.width() {
184            self.cursor.x = 0;
185            self.cursor.y += 1;
186        }
187    }
188
189    fn num_lines(&self) -> usize {
190        self.cursor.y as usize + 1
191    }
192}
193
194impl Wrap for Char {
195    fn clear(&mut self) {
196        self.cursor = Coord::new(0, 0);
197    }
198
199    fn process_character<F: Frame, C: ColModify>(
200        &mut self,
201        character: char,
202        style: Style,
203        context: ViewContext<C>,
204        frame: &mut F,
205    ) {
206        match character {
207            '\n' => {
208                self.cursor.x = 0;
209                self.cursor.y += 1;
210            }
211            '\r' => self.cursor.x = 0,
212            other => {
213                let view_cell = ViewCell {
214                    character: Some(other),
215                    style,
216                };
217                frame.set_cell_relative(self.cursor, 0, view_cell, context);
218                self.cursor += Coord::new(1, 0);
219                if self.cursor.x >= context.size.width() as i32 {
220                    self.cursor.x = 0;
221                    self.cursor.y += 1;
222                }
223            }
224        }
225    }
226
227    fn num_lines(&self) -> usize {
228        self.cursor.y as usize + 1
229    }
230}
231
232mod private_wrap {
233    pub trait Sealed {}
234    impl Sealed for super::None {}
235    impl Sealed for super::Word {}
236    impl Sealed for super::Char {}
237}