1use crate::{Grapheme, TextPosition};
2use std::borrow::Cow;
3use std::fmt::Debug;
4use std::ops::Range;
5
6#[derive(Debug)]
8#[deprecated(since = "1.1.0", note = "discontinued api")]
9pub struct Glyph<'a> {
10 glyph: Cow<'a, str>,
12 text_bytes: Range<usize>,
14 screen_pos: (u16, u16),
17 screen_width: u16,
19 pos: TextPosition,
21}
22
23#[allow(deprecated)]
24impl<'a> Glyph<'a> {
25 pub fn new(
26 glyph: Cow<'a, str>,
27 text_bytes: Range<usize>,
28 screen_pos: (u16, u16),
29 screen_width: u16,
30 pos: TextPosition,
31 ) -> Self {
32 Self {
33 glyph,
34 text_bytes,
35 screen_pos,
36 screen_width,
37 pos,
38 }
39 }
40
41 pub fn glyph(&'a self) -> &'a str {
43 self.glyph.as_ref()
44 }
45
46 pub fn text_bytes(&self) -> Range<usize> {
48 self.text_bytes.clone()
49 }
50
51 pub fn pos(&self) -> TextPosition {
53 self.pos
54 }
55
56 pub fn screen_pos(&self) -> (u16, u16) {
58 self.screen_pos
59 }
60
61 pub fn screen_width(&self) -> u16 {
63 self.screen_width
64 }
65}
66
67#[derive(Debug)]
75pub(crate) struct GlyphIter<Iter> {
76 iter: Iter,
77
78 pos: TextPosition,
79
80 screen_offset: u16,
81 screen_width: u16,
82 screen_pos: (u16, u16),
83
84 tabs: u16,
85 show_ctrl: bool,
86 line_break: bool,
87}
88
89impl<'a, Iter> GlyphIter<Iter>
90where
91 Iter: Iterator<Item = Grapheme<'a>>,
92{
93 pub(crate) fn new(pos: TextPosition, iter: Iter) -> Self {
95 Self {
96 iter,
97 pos,
98 screen_offset: 0,
99 screen_width: u16::MAX,
100 screen_pos: Default::default(),
101 tabs: 8,
102 show_ctrl: false,
103 line_break: true,
104 }
105 }
106
107 pub(crate) fn set_screen_offset(&mut self, offset: u16) {
109 self.screen_offset = offset;
110 }
111
112 pub(crate) fn set_screen_width(&mut self, width: u16) {
114 self.screen_width = width;
115 }
116
117 pub(crate) fn set_tabs(&mut self, tabs: u16) {
119 self.tabs = tabs;
120 }
121
122 pub(crate) fn set_line_break(&mut self, line_break: bool) {
124 self.line_break = line_break;
125 }
126
127 pub(crate) fn set_show_ctrl(&mut self, show_ctrl: bool) {
129 self.show_ctrl = show_ctrl;
130 }
131}
132
133#[allow(deprecated)]
134impl<'a, Iter> Iterator for GlyphIter<Iter>
135where
136 Iter: Iterator<Item = Grapheme<'a>>,
137{
138 type Item = Glyph<'a>;
139
140 fn next(&mut self) -> Option<Self::Item> {
141 for grapheme in self.iter.by_ref() {
142 let (grapheme, grapheme_bytes) = grapheme.into_parts();
143
144 let glyph;
145 let len: u16;
146 let mut lbrk = false;
147
148 match grapheme.as_ref() {
151 "\n" | "\r\n" if self.line_break => {
152 lbrk = true;
153 len = if self.show_ctrl { 1 } else { 0 };
154 glyph = Cow::Borrowed(if self.show_ctrl { "\u{2424}" } else { "" });
155 }
156 "\n" | "\r\n" if !self.line_break => {
157 lbrk = false;
158 len = 1;
159 glyph = Cow::Borrowed("\u{2424}");
160 }
161 "\t" => {
162 len = self.tabs - (self.screen_pos.0 % self.tabs);
163 glyph = Cow::Borrowed(if self.show_ctrl { "\u{2409}" } else { " " });
164 }
165 c if ("\x00".."\x20").contains(&c) => {
166 static CCHAR: [&str; 32] = [
167 "\u{2400}", "\u{2401}", "\u{2402}", "\u{2403}", "\u{2404}", "\u{2405}",
168 "\u{2406}", "\u{2407}", "\u{2408}", "\u{2409}", "\u{240A}", "\u{240B}",
169 "\u{240C}", "\u{240D}", "\u{240E}", "\u{240F}", "\u{2410}", "\u{2411}",
170 "\u{2412}", "\u{2413}", "\u{2414}", "\u{2415}", "\u{2416}", "\u{2417}",
171 "\u{2418}", "\u{2419}", "\u{241A}", "\u{241B}", "\u{241C}", "\u{241D}",
172 "\u{241E}", "\u{241F}",
173 ];
174 let c0 = c.bytes().next().expect("byte");
175 len = 1;
176 glyph = Cow::Borrowed(if self.show_ctrl {
177 CCHAR[c0 as usize]
178 } else {
179 "\u{FFFD}"
180 });
181 }
182 c => {
183 len = unicode_display_width::width(c) as u16;
184 glyph = grapheme;
185 }
186 }
187
188 let pos = self.pos;
189 let screen_pos = self.screen_pos;
190
191 if lbrk {
192 self.screen_pos.0 = 0;
193 self.screen_pos.1 += 1;
194 self.pos.x = 0;
195 self.pos.y += 1;
196 } else {
197 self.screen_pos.0 += len;
198 self.pos.x += 1;
199 }
200
201 if screen_pos.0 < self.screen_offset {
203 if screen_pos.0 + len > self.screen_offset {
204 return Some(Glyph {
207 glyph: Cow::Borrowed("\u{2203}"),
208 text_bytes: grapheme_bytes,
209 screen_width: screen_pos.0 + len - self.screen_offset,
210 pos,
211 screen_pos: (0, screen_pos.1),
212 });
213 } else {
214 }
216 } else if screen_pos.0 + len > self.screen_offset + self.screen_width {
217 if screen_pos.0 < self.screen_offset + self.screen_width {
218 return Some(Glyph {
221 glyph: Cow::Borrowed("\u{2203}"),
222 text_bytes: grapheme_bytes,
223 screen_width: screen_pos.0 + len - (self.screen_offset + self.screen_width),
224 pos,
225 screen_pos: (screen_pos.0 - self.screen_offset, screen_pos.1),
226 });
227 } else {
228 if !self.line_break {
230 break;
231 }
232 }
233 } else {
234 return Some(Glyph {
235 glyph,
236 text_bytes: grapheme_bytes,
237 screen_width: len,
238 pos,
239 screen_pos: (screen_pos.0 - self.screen_offset, screen_pos.1),
240 });
241 }
242 }
243
244 None
245 }
246}
247
248#[cfg(test)]
249mod test_glyph {
250 use crate::glyph::GlyphIter;
251 use crate::grapheme::RopeGraphemes;
252 use crate::TextPosition;
253 use ropey::Rope;
254
255 #[test]
256 fn test_glyph1() {
257 let s = Rope::from(
258 r#"0123456789
259abcdefghij
260jklöjklöjk
261uiopü+uiop"#,
262 );
263 let r = RopeGraphemes::new(0, s.byte_slice(..));
264 let mut glyphs = GlyphIter::new(TextPosition::new(0, 0), r);
265
266 let n = glyphs.next().unwrap();
267 assert_eq!(n.glyph(), "0");
268 assert_eq!(n.text_bytes(), 0..1);
269 assert_eq!(n.screen_pos(), (0, 0));
270 assert_eq!(n.pos(), TextPosition::new(0, 0));
271 assert_eq!(n.screen_width(), 1);
272
273 let n = glyphs.next().unwrap();
274 assert_eq!(n.glyph(), "1");
275 assert_eq!(n.text_bytes(), 1..2);
276 assert_eq!(n.screen_pos(), (1, 0));
277 assert_eq!(n.pos(), TextPosition::new(1, 0));
278 assert_eq!(n.screen_width(), 1);
279
280 let n = glyphs.next().unwrap();
281 assert_eq!(n.glyph(), "2");
282 assert_eq!(n.text_bytes(), 2..3);
283 assert_eq!(n.screen_pos(), (2, 0));
284 assert_eq!(n.pos(), TextPosition::new(2, 0));
285 assert_eq!(n.screen_width(), 1);
286
287 let n = glyphs.nth(7).unwrap();
288 assert_eq!(n.glyph(), "");
289 assert_eq!(n.text_bytes(), 10..11);
290 assert_eq!(n.screen_pos(), (10, 0));
291 assert_eq!(n.pos(), TextPosition::new(10, 0));
292 assert_eq!(n.screen_width(), 0);
293
294 let n = glyphs.next().unwrap();
295 assert_eq!(n.glyph(), "a");
296 assert_eq!(n.text_bytes(), 11..12);
297 assert_eq!(n.screen_pos(), (0, 1));
298 assert_eq!(n.pos(), TextPosition::new(0, 1));
299 assert_eq!(n.screen_width(), 1);
300 }
301
302 #[test]
303 fn test_glyph2() {
304 let s = Rope::from(
306 r#"0123456789
307abcdefghij
308jklöjklöjk
309uiopü+uiop"#,
310 );
311 let r = RopeGraphemes::new(0, s.byte_slice(..));
312 let mut glyphs = GlyphIter::new(TextPosition::new(0, 0), r);
313 glyphs.set_screen_offset(2);
314 glyphs.set_screen_width(100);
315
316 let n = glyphs.next().unwrap();
317 assert_eq!(n.glyph(), "2");
318 assert_eq!(n.text_bytes(), 2..3);
319 assert_eq!(n.screen_pos(), (0, 0));
320 assert_eq!(n.pos(), TextPosition::new(2, 0));
321 assert_eq!(n.screen_width(), 1);
322
323 let n = glyphs.next().unwrap();
324 assert_eq!(n.glyph(), "3");
325 assert_eq!(n.text_bytes(), 3..4);
326 assert_eq!(n.screen_pos(), (1, 0));
327 assert_eq!(n.pos(), TextPosition::new(3, 0));
328 assert_eq!(n.screen_width(), 1);
329
330 let n = glyphs.nth(6).unwrap();
331 assert_eq!(n.glyph(), "");
332 assert_eq!(n.text_bytes(), 10..11);
333 assert_eq!(n.screen_pos(), (8, 0));
334 assert_eq!(n.pos(), TextPosition::new(10, 0));
335 assert_eq!(n.screen_width(), 0);
336
337 let n = glyphs.next().unwrap();
338 assert_eq!(n.glyph(), "c");
339 assert_eq!(n.text_bytes(), 13..14);
340 assert_eq!(n.screen_pos(), (0, 1));
341 assert_eq!(n.pos(), TextPosition::new(2, 1));
342 assert_eq!(n.screen_width(), 1);
343 }
344
345 #[test]
346 fn test_glyph3() {
347 let s = Rope::from(
349 r#"0123456789
350abcdefghij
351jklöjklöjk
352uiopü+uiop"#,
353 );
354 let r = RopeGraphemes::new(0, s.byte_slice(..));
355 let mut glyphs = GlyphIter::new(TextPosition::new(0, 0), r);
356 glyphs.set_screen_offset(2);
357 glyphs.set_screen_width(6);
358
359 let n = glyphs.next().unwrap();
360 assert_eq!(n.glyph(), "2");
361 assert_eq!(n.text_bytes(), 2..3);
362 assert_eq!(n.screen_pos(), (0, 0));
363 assert_eq!(n.pos(), TextPosition::new(2, 0));
364 assert_eq!(n.screen_width(), 1);
365
366 let n = glyphs.next().unwrap();
367 assert_eq!(n.glyph(), "3");
368 assert_eq!(n.text_bytes(), 3..4);
369 assert_eq!(n.screen_pos(), (1, 0));
370 assert_eq!(n.pos(), TextPosition::new(3, 0));
371 assert_eq!(n.screen_width(), 1);
372
373 let n = glyphs.nth(2).unwrap();
374 assert_eq!(n.glyph(), "6");
375
376 let n = glyphs.next().unwrap();
377 assert_eq!(n.glyph(), "7");
378 assert_eq!(n.text_bytes(), 7..8);
379 assert_eq!(n.screen_pos(), (5, 0));
380 assert_eq!(n.pos(), TextPosition::new(7, 0));
381 assert_eq!(n.screen_width(), 1);
382
383 let n = glyphs.next().unwrap();
384 assert_eq!(n.glyph(), "c");
385 assert_eq!(n.text_bytes(), 13..14);
386 assert_eq!(n.screen_pos(), (0, 1));
387 assert_eq!(n.pos(), TextPosition::new(2, 1));
388 assert_eq!(n.screen_width(), 1);
389 }
390
391 #[test]
392 fn test_glyph4() {
393 let s = Rope::from(
395 "012\t3456789
396abcdefghij
397jklöjklöjk
398uiopü+uiop",
399 );
400 let r = RopeGraphemes::new(0, s.byte_slice(..));
401 let mut glyphs = GlyphIter::new(TextPosition::new(0, 0), r);
402 glyphs.set_screen_offset(2);
403 glyphs.set_screen_width(100);
404
405 let n = glyphs.next().unwrap();
406 assert_eq!(n.glyph(), "2");
407 assert_eq!(n.text_bytes(), 2..3);
408 assert_eq!(n.screen_pos(), (0, 0));
409 assert_eq!(n.pos(), TextPosition::new(2, 0));
410 assert_eq!(n.screen_width(), 1);
411
412 let n = glyphs.next().unwrap();
413 assert_eq!(n.glyph(), " ");
414 assert_eq!(n.text_bytes(), 3..4);
415 assert_eq!(n.screen_pos(), (1, 0));
416 assert_eq!(n.pos(), TextPosition::new(3, 0));
417 assert_eq!(n.screen_width(), 5);
418
419 let n = glyphs.nth(7).unwrap();
420 assert_eq!(n.glyph(), "");
421 assert_eq!(n.text_bytes(), 11..12);
422 assert_eq!(n.screen_pos(), (13, 0));
423 assert_eq!(n.pos(), TextPosition::new(11, 0));
424 assert_eq!(n.screen_width(), 0);
425
426 let n = glyphs.next().unwrap();
427 assert_eq!(n.glyph(), "c");
428 assert_eq!(n.text_bytes(), 14..15);
429 assert_eq!(n.screen_pos(), (0, 1));
430 assert_eq!(n.pos(), TextPosition::new(2, 1));
431 assert_eq!(n.screen_width(), 1);
432 }
433
434 #[test]
435 fn test_glyph5() {
436 let s = Rope::from(
438 "0\t12345678\t9
439abcdefghij
440jklöjklöjk
441uiopü+uiop",
442 );
443 let r = RopeGraphemes::new(0, s.byte_slice(..));
444 let mut glyphs = GlyphIter::new(TextPosition::new(0, 0), r);
445 glyphs.set_screen_offset(2);
446 glyphs.set_screen_width(20);
447
448 let n = glyphs.next().unwrap();
449 assert_eq!(n.glyph(), "∃");
450 assert_eq!(n.text_bytes(), 1..2);
451 assert_eq!(n.screen_pos(), (0, 0));
452 assert_eq!(n.pos(), TextPosition::new(1, 0));
453 assert_eq!(n.screen_width(), 6);
454
455 let n = glyphs.next().unwrap();
456 assert_eq!(n.glyph(), "1");
457 assert_eq!(n.text_bytes(), 2..3);
458 assert_eq!(n.screen_pos(), (6, 0));
459 assert_eq!(n.pos(), TextPosition::new(2, 0));
460 assert_eq!(n.screen_width(), 1);
461
462 let n = glyphs.nth(6).unwrap();
463 assert_eq!(n.glyph(), "8");
464
465 let n = glyphs.next().unwrap();
466 assert_eq!(n.glyph(), "∃");
467 assert_eq!(n.text_bytes(), 10..11);
468 assert_eq!(n.screen_pos(), (14, 0));
469 assert_eq!(n.pos(), TextPosition::new(10, 0));
470 assert_eq!(n.screen_width(), 2);
471
472 let n = glyphs.next().unwrap();
473 assert_eq!(n.glyph(), "c");
474 assert_eq!(n.text_bytes(), 15..16);
475 assert_eq!(n.screen_pos(), (0, 1));
476 assert_eq!(n.pos(), TextPosition::new(2, 1));
477 assert_eq!(n.screen_width(), 1);
478 }
479}