1use crate::clipboard::{Clipboard, global_clipboard};
2use crate::core::{TextCore, TextString};
3#[allow(deprecated)]
4use crate::glyph::{Glyph, GlyphIter};
5use crate::glyph2::{Glyph2, GlyphIter2, TextWrap2};
6use crate::grapheme::StrGraphemes;
7use crate::text_mask_core::mask::{EditDirection, Mask, MaskToken};
8use crate::text_store::SkipLine;
9use crate::undo_buffer::{UndoBuffer, UndoEntry, UndoVec};
10use crate::{Cursor, Grapheme, TextError, TextPosition, TextRange, upos_type};
11use format_num_pattern::core::{clean_num, map_num};
12use format_num_pattern::{CurrencySym, NumberFormat, NumberSymbols};
13use std::borrow::Cow;
14use std::iter::once;
15use std::ops::Range;
16use std::{fmt, slice};
17use unicode_segmentation::UnicodeSegmentation;
18
19#[derive(Debug, Clone)]
21pub struct MaskedCore {
22 masked: TextCore<TextString>,
24 sym: Option<NumberSymbols>,
26 mask: Vec<MaskToken>,
28}
29
30impl Default for MaskedCore {
31 fn default() -> Self {
32 let mut value = TextCore::new(
33 Some(Box::new(UndoVec::new(99))),
34 Some(Box::new(global_clipboard())),
35 );
36 value.set_glyph_line_break(false);
37
38 Self {
39 masked: value,
40 sym: None,
41 mask: Default::default(),
42 }
43 }
44}
45
46impl MaskedCore {
47 pub fn new() -> Self {
48 Self::default()
49 }
50
51 pub fn set_num_symbols(&mut self, sym: NumberSymbols) {
55 self.sym = Some(sym);
56 }
57
58 fn dec_sep(&self) -> char {
59 if let Some(sym) = &self.sym {
60 sym.decimal_sep
61 } else {
62 '.'
63 }
64 }
65
66 fn grp_sep(&self) -> char {
67 if let Some(sym) = &self.sym {
68 sym.decimal_grp.unwrap_or(' ')
72 } else {
73 ','
74 }
75 }
76
77 fn neg_sym(&self) -> char {
78 if let Some(sym) = &self.sym {
79 sym.negative_sym
80 } else {
81 '-'
82 }
83 }
84
85 fn pos_sym(&self) -> char {
86 if let Some(sym) = &self.sym {
87 sym.positive_sym
88 } else {
89 ' '
90 }
91 }
92
93 pub fn set_mask<S: AsRef<str>>(&mut self, s: S) -> Result<(), fmt::Error> {
96 self.mask = Self::parse_mask(s.as_ref())?;
97 self.clear();
98 Ok(())
99 }
100
101 #[allow(clippy::needless_range_loop)]
102 fn parse_mask(mask_str: &str) -> Result<Vec<MaskToken>, fmt::Error> {
103 let mut out = Vec::<MaskToken>::new();
104
105 let mut start_sub = 0;
106 let mut start_sec = 0;
107 let mut sec_id = 0;
108 let mut last_mask = Mask::None;
109 let mut dec_dir = EditDirection::Rtol;
110 let mut esc = false;
111 let mut idx = 0;
112 for m in mask_str.graphemes(true).chain(once("")) {
113 let mask = if esc {
114 esc = false;
115 Mask::Separator(Box::from(m))
116 } else {
117 match m {
118 "0" => Mask::Digit0(dec_dir),
119 "9" => Mask::Digit(dec_dir),
120 "#" => Mask::Numeric(dec_dir),
121 "." => Mask::DecimalSep,
122 "," => Mask::GroupingSep,
123 "-" => Mask::Sign,
124 "+" => Mask::Plus,
125 "h" => Mask::Hex,
126 "H" => Mask::Hex0,
127 "o" => Mask::Oct,
128 "O" => Mask::Oct0,
129 "d" => Mask::Dec,
130 "D" => Mask::Dec0,
131 "l" => Mask::Letter,
132 "a" => Mask::LetterOrDigit,
133 "c" => Mask::LetterDigitSpace,
134 "_" => Mask::AnyChar,
135 "" => Mask::None,
136 " " => Mask::Separator(Box::from(m)),
137 "\\" => {
138 esc = true;
139 continue;
140 }
141 _ => return Err(fmt::Error),
142 }
143 };
144
145 match mask {
146 Mask::Digit0(_)
147 | Mask::Digit(_)
148 | Mask::Numeric(_)
149 | Mask::GroupingSep
150 | Mask::Sign
151 | Mask::Plus => {
152 }
154 Mask::DecimalSep => {
155 dec_dir = EditDirection::Ltor;
156 }
157 Mask::Hex0
158 | Mask::Hex
159 | Mask::Oct0
160 | Mask::Oct
161 | Mask::Dec0
162 | Mask::Dec
163 | Mask::Letter
164 | Mask::LetterOrDigit
165 | Mask::LetterDigitSpace
166 | Mask::AnyChar
167 | Mask::Separator(_) => {
168 dec_dir = EditDirection::Rtol
170 }
171 Mask::None => {
172 }
174 }
175
176 if matches!(mask, Mask::Separator(_)) || mask.section() != last_mask.section() {
177 for j in start_sec..idx {
178 out[j].sec_id = sec_id;
179 out[j].sec_start = start_sec as upos_type;
180 out[j].sec_end = idx as upos_type;
181 }
182 sec_id += 1;
183 start_sec = idx;
184 }
185 if matches!(mask, Mask::Separator(_)) || mask.sub_section() != last_mask.sub_section() {
186 for j in start_sub..idx {
187 out[j].sub_start = start_sub as upos_type;
188 out[j].sub_end = idx as upos_type;
189 }
190 start_sub = idx;
191 }
192
193 let tok = MaskToken {
194 sec_id: 0,
195 sec_start: 0,
196 sec_end: 0,
197 sub_start: 0,
198 sub_end: 0,
199 peek_left: last_mask,
200 right: mask.clone(),
201 edit: mask.edit_value().into(),
202 };
203 out.push(tok);
204
205 idx += 1;
206 last_mask = mask;
207 }
208 for j in start_sec..out.len() {
209 out[j].sec_id = sec_id;
210 out[j].sec_start = start_sec as upos_type;
211 out[j].sec_end = mask_str.graphemes(true).count() as upos_type;
212 }
213 for j in start_sub..out.len() {
214 out[j].sub_start = start_sub as upos_type;
215 out[j].sub_end = mask_str.graphemes(true).count() as upos_type;
216 }
217
218 Ok(out)
219 }
220
221 pub fn mask(&self) -> String {
223 use std::fmt::Write;
224
225 let mut buf = String::new();
226 for t in self.mask.iter() {
227 _ = write!(buf, "{}", t.right);
228 }
229 buf
230 }
231}
232
233impl MaskedCore {
234 pub fn set_clipboard(&mut self, clip: Option<Box<dyn Clipboard + 'static>>) {
236 self.masked.set_clipboard(clip);
237 }
238
239 pub fn clipboard(&self) -> Option<&dyn Clipboard> {
241 self.masked.clipboard()
242 }
243}
244
245impl MaskedCore {
246 #[inline]
248 pub fn set_undo_buffer(&mut self, undo: Option<Box<dyn UndoBuffer>>) {
249 self.masked.set_undo_buffer(undo);
250 }
251
252 #[inline]
254 pub fn set_undo_count(&mut self, n: u32) {
255 self.masked.set_undo_count(n);
256 }
257
258 #[inline]
260 pub fn begin_undo_seq(&mut self) {
261 self.masked.begin_undo_seq();
262 }
263
264 #[inline]
266 pub fn end_undo_seq(&mut self) {
267 self.masked.end_undo_seq();
268 }
269
270 #[inline]
272 pub fn undo_buffer(&self) -> Option<&dyn UndoBuffer> {
273 self.masked.undo_buffer()
274 }
275
276 #[inline]
278 pub fn undo_buffer_mut(&mut self) -> Option<&mut dyn UndoBuffer> {
279 self.masked.undo_buffer_mut()
280 }
281
282 pub fn undo(&mut self) -> bool {
284 self.masked.undo()
285 }
286
287 pub fn redo(&mut self) -> bool {
289 self.masked.redo()
290 }
291
292 pub fn recent_replay_log(&mut self) -> Vec<UndoEntry> {
294 self.masked.recent_replay_log()
295 }
296
297 pub fn replay_log(&mut self, replay: &[UndoEntry]) {
299 self.masked.replay_log(replay)
300 }
301}
302
303impl MaskedCore {
304 #[inline]
309 pub fn set_styles(&mut self, new_styles: Vec<(Range<usize>, usize)>) {
310 self.masked.set_styles(new_styles);
311 }
312
313 #[inline]
318 pub fn add_style(&mut self, range: Range<usize>, style: usize) {
319 self.masked.add_style(range, style);
320 }
321
322 #[inline]
326 pub fn remove_style(&mut self, range: Range<usize>, style: usize) {
327 self.masked.remove_style(range, style);
328 }
329
330 #[inline]
334 pub(crate) fn styles_at_page(&self, pos: usize, range: Range<usize>, buf: &mut Vec<usize>) {
335 self.masked.styles_at_page(pos, range, buf);
336 }
337
338 pub fn styles_in(&self, range: Range<usize>, buf: &mut Vec<(Range<usize>, usize)>) {
340 self.masked.styles_in(range, buf)
341 }
342
343 #[inline]
345 pub fn styles_at(&self, byte_pos: usize, buf: &mut Vec<(Range<usize>, usize)>) {
346 self.masked.styles_at(byte_pos, buf);
347 }
348
349 #[inline]
352 pub fn style_match(&self, byte_pos: usize, style: usize) -> Option<Range<usize>> {
353 self.masked.style_match(byte_pos, style)
354 }
355
356 #[inline]
358 pub fn styles(&self) -> Option<impl Iterator<Item = (Range<usize>, usize)> + '_> {
359 self.masked.styles()
360 }
361}
362
363impl MaskedCore {
364 pub fn set_cursor(&mut self, cursor: upos_type, extend_selection: bool) -> bool {
370 self.masked
371 .set_cursor(TextPosition::new(cursor, 0), extend_selection)
372 }
373
374 fn number_cursor(&self, range: Range<upos_type>) -> upos_type {
376 for (i, t) in self.mask[range.start as usize..range.end as usize]
377 .iter()
378 .enumerate()
379 .rev()
380 {
381 match t.right {
382 Mask::Digit(EditDirection::Rtol)
383 | Mask::Digit0(EditDirection::Rtol)
384 | Mask::Numeric(EditDirection::Rtol) => {
385 return range.start + i as upos_type + 1;
386 }
387 _ => {}
388 }
389 }
390 range.start
391 }
392
393 pub fn section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
396 if cursor as usize >= self.mask.len() {
397 return None;
398 }
399
400 let mask = &self.mask[cursor as usize];
401
402 if mask.right.is_number() {
403 Some(self.number_cursor(mask.sec_start..mask.sec_end))
404 } else if mask.right.is_separator() {
405 None
406 } else if mask.right.is_none() {
407 None
408 } else {
409 Some(mask.sec_start)
410 }
411 }
412
413 pub fn next_section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
415 if cursor as usize >= self.mask.len() {
416 return None;
417 }
418
419 let mut mask = &self.mask[cursor as usize];
420 let mut next;
421 loop {
422 if mask.right.is_none() {
423 return None;
424 }
425
426 next = mask.sec_end;
427 mask = &self.mask[next as usize];
428
429 if mask.right.is_number() {
430 return Some(self.number_cursor(mask.sec_start..mask.sec_end));
431 } else if mask.right.is_separator() {
432 continue;
433 } else if mask.right.is_none() {
434 return None;
435 } else {
436 return Some(mask.sec_start);
437 }
438 }
439 }
440
441 pub fn prev_section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
443 if cursor as usize >= self.mask.len() {
444 return None;
445 }
446
447 let mut prev = self.mask[cursor as usize].sec_start;
448 let mut mask = &self.mask[prev as usize];
449
450 loop {
451 if mask.peek_left.is_none() {
452 return None;
453 }
454
455 prev = self.mask[mask.sec_start as usize - 1].sec_start;
456 mask = &self.mask[prev as usize];
457
458 if mask.right.is_number() {
459 return Some(self.number_cursor(mask.sec_start..mask.sec_end));
460 } else if mask.right.is_separator() {
461 continue;
462 } else {
463 return Some(mask.sec_start);
464 }
465 }
466 }
467
468 pub fn is_section_boundary(&self, pos: upos_type) -> bool {
470 if pos == 0 {
471 return false;
472 }
473 if pos as usize >= self.mask.len() {
474 return false;
475 }
476 let prev = &self.mask[pos as usize - 1];
477 let mask = &self.mask[pos as usize];
478 prev.sec_id != mask.sec_id
479 }
480
481 pub fn section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
484 if cursor as usize >= self.mask.len() {
485 return None;
486 }
487
488 let mask = &self.mask[cursor as usize];
489 if mask.right.is_number() {
490 Some(mask.sec_start..mask.sec_end)
491 } else if mask.right.is_separator() {
492 None
493 } else if mask.right.is_none() {
494 None
495 } else {
496 Some(mask.sec_start..mask.sec_end)
497 }
498 }
499
500 pub fn next_section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
502 if cursor as usize >= self.mask.len() {
503 return None;
504 }
505
506 let mut mask = &self.mask[cursor as usize];
507 let mut next;
508 loop {
509 if mask.right.is_none() {
510 return None;
511 }
512
513 next = mask.sec_end;
514 mask = &self.mask[next as usize];
515
516 if mask.right.is_number() {
517 return Some(mask.sec_start..mask.sec_end);
518 } else if mask.right.is_separator() {
519 continue;
520 } else if mask.right.is_none() {
521 return None;
522 } else {
523 return Some(mask.sec_start..mask.sec_end);
524 }
525 }
526 }
527
528 pub fn prev_section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
530 if cursor as usize >= self.mask.len() {
531 return None;
532 }
533
534 let mut prev = self.mask[cursor as usize].sec_start;
535 let mut mask = &self.mask[prev as usize];
536 loop {
537 if mask.peek_left.is_none() {
538 return None;
539 }
540
541 prev = self.mask[mask.sec_start as usize - 1].sec_start;
542 mask = &self.mask[prev as usize];
543
544 if mask.right.is_number() {
545 return Some(mask.sec_start..mask.sec_end);
546 } else if mask.right.is_separator() {
547 continue;
548 } else {
549 return Some(mask.sec_start..mask.sec_end);
550 }
551 }
552 }
553
554 #[inline]
557 pub fn set_default_cursor(&mut self) {
558 if let Some(pos) = self.section_cursor(0) {
559 self.masked.set_cursor(TextPosition::new(pos, 0), false);
560 } else if let Some(pos) = self.next_section_cursor(0) {
561 self.masked.set_cursor(TextPosition::new(pos, 0), false);
562 } else {
563 self.masked.set_cursor(TextPosition::new(0, 0), false);
564 }
565 }
566
567 #[inline]
569 pub fn cursor(&self) -> upos_type {
570 self.masked.cursor().x
571 }
572
573 #[inline]
575 pub fn anchor(&self) -> upos_type {
576 self.masked.anchor().x
577 }
578
579 #[inline]
581 pub fn has_selection(&self) -> bool {
582 self.masked.has_selection()
583 }
584
585 #[inline]
587 pub fn set_selection(&mut self, anchor: upos_type, cursor: upos_type) -> bool {
588 self.masked
589 .set_selection(TextPosition::new(anchor, 0), TextPosition::new(cursor, 0))
590 }
591
592 #[inline]
594 pub fn select_all(&mut self) -> bool {
595 self.masked.select_all()
596 }
597
598 #[inline]
600 pub fn selection(&self) -> Range<upos_type> {
601 let mut v = self.masked.selection();
602 if v.start == TextPosition::new(0, 1) {
603 v.start = TextPosition::new(self.line_width(), 0);
604 }
605 if v.end == TextPosition::new(0, 1) {
606 v.end = TextPosition::new(self.line_width(), 0);
607 }
608 v.start.x..v.end.x
609 }
610
611 #[inline]
613 pub fn selected_text(&self) -> &str {
614 match self
615 .masked
616 .str_slice(self.masked.selection())
617 .expect("valid_range")
618 {
619 Cow::Borrowed(v) => v,
620 Cow::Owned(_) => {
621 unreachable!()
622 }
623 }
624 }
625}
626
627impl MaskedCore {
628 #[inline]
630 pub fn is_empty(&self) -> bool {
631 self.masked.text().as_str() == self.default_value()
632 }
633
634 #[inline]
637 pub fn byte_at(&self, pos: upos_type) -> Result<Range<usize>, TextError> {
638 self.masked.byte_at(TextPosition::new(pos, 0))
639 }
640
641 #[inline]
643 pub fn bytes_at_range(&self, range: Range<upos_type>) -> Result<Range<usize>, TextError> {
644 self.masked
645 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))
646 }
647
648 #[inline]
651 pub fn byte_pos(&self, byte: usize) -> Result<upos_type, TextError> {
652 Ok(self.masked.byte_pos(byte)?.x)
653 }
654
655 #[inline]
657 pub fn byte_range(&self, bytes: Range<usize>) -> Result<Range<upos_type>, TextError> {
658 let r = self.masked.byte_range(bytes)?;
659 Ok(r.start.x..r.end.x)
660 }
661
662 #[inline]
664 pub fn str_slice_byte(&self, range: Range<usize>) -> Result<Cow<'_, str>, TextError> {
665 self.masked.str_slice_byte(range)
666 }
667
668 #[inline]
670 pub fn str_slice(&self, range: Range<upos_type>) -> Result<Cow<'_, str>, TextError> {
671 self.masked
672 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
673 }
674
675 #[inline]
678 #[deprecated(since = "1.1.0", note = "discontinued api")]
679 #[allow(deprecated)]
680 pub fn glyphs(
681 &self,
682 rows: Range<upos_type>,
683 screen_offset: u16,
684 screen_width: u16,
685 ) -> Result<impl Iterator<Item = Glyph<'_>>, TextError> {
686 let grapheme_iter = self.masked.graphemes(
687 TextRange::new((0, rows.start), (0, rows.end)),
688 TextPosition::new(0, rows.start),
689 )?;
690
691 let mask_iter = self.mask.iter();
692
693 let sym_neg = || self.neg_sym().to_string();
694 let sym_dec = || self.dec_sep().to_string();
695 let sym_grp = || self.grp_sep().to_string();
696 let sym_pos = || self.pos_sym().to_string();
697
698 let iter = grapheme_iter
699 .zip(mask_iter)
700 .map(move |(g, t)| match (&t.right, g.grapheme()) {
701 (Mask::Numeric(_), "-") => Grapheme::new(Cow::Owned(sym_neg()), g.text_bytes()),
702 (Mask::DecimalSep, ".") => Grapheme::new(Cow::Owned(sym_dec()), g.text_bytes()),
703 (Mask::GroupingSep, ",") => Grapheme::new(Cow::Owned(sym_grp()), g.text_bytes()),
704 (Mask::GroupingSep, "-") => Grapheme::new(Cow::Owned(sym_neg()), g.text_bytes()),
705 (Mask::Sign, "-") => Grapheme::new(Cow::Owned(sym_neg()), g.text_bytes()),
706 (Mask::Sign, _) => Grapheme::new(Cow::Owned(sym_pos()), g.text_bytes()),
707 (_, _) => g,
708 });
709
710 let mut it = GlyphIter::new(TextPosition::new(0, rows.start), iter);
711 it.set_screen_offset(screen_offset);
712 it.set_screen_width(screen_width);
713 it.set_tabs(self.masked.tab_width());
714 it.set_show_ctrl(self.masked.glyph_ctrl());
715 it.set_line_break(self.masked.glyph_line_break());
716 Ok(it)
717 }
718
719 #[inline]
724 #[deprecated(since = "1.1.0", note = "discontinued api")]
725 #[allow(deprecated)]
726 pub fn condensed_glyphs(
727 &self,
728 rows: Range<upos_type>,
729 screen_offset: u16,
730 screen_width: u16,
731 ) -> Result<impl Iterator<Item = Glyph<'_>>, TextError> {
732 let grapheme_iter = self.masked.graphemes(
733 TextRange::new((0, rows.start), (0, rows.end)),
734 TextPosition::new(0, rows.start),
735 )?;
736
737 let mask_iter = self.mask.iter();
738
739 let sym_neg = || self.neg_sym().to_string();
740 let sym_dec = || self.dec_sep().to_string();
741 let sym_grp = || self.grp_sep().to_string();
742 let sym_pos = || self.pos_sym().to_string();
743
744 let iter =
745 grapheme_iter
746 .zip(mask_iter)
747 .filter_map(move |(g, t)| match (&t.right, g.grapheme()) {
748 (Mask::Numeric(_), "-") => {
749 Some(Grapheme::new(Cow::Owned(sym_neg()), g.text_bytes()))
750 }
751 (Mask::DecimalSep, ".") => {
752 Some(Grapheme::new(Cow::Owned(sym_dec()), g.text_bytes()))
753 }
754 (Mask::GroupingSep, ",") => {
755 Some(Grapheme::new(Cow::Owned(sym_grp()), g.text_bytes()))
756 }
757 (Mask::GroupingSep, "-") => {
758 Some(Grapheme::new(Cow::Owned(sym_neg()), g.text_bytes()))
759 }
760 (Mask::Sign, "-") => Some(Grapheme::new(Cow::Owned(sym_neg()), g.text_bytes())),
761
762 (Mask::Numeric(_), " ") => None,
763 (Mask::Digit(_), " ") => None,
764 (Mask::DecimalSep, " ") => None,
765 (Mask::GroupingSep, " ") => None,
766 (Mask::Sign, _) => {
767 if self.pos_sym() != ' ' {
768 Some(Grapheme::new(Cow::Owned(sym_pos()), g.text_bytes()))
769 } else {
770 None
771 }
772 }
773 (Mask::Hex, " ") => None,
774 (Mask::Oct, " ") => None,
775 (Mask::Dec, " ") => None,
776
777 (_, _) => Some(g),
778 });
779
780 let mut it = GlyphIter::new(TextPosition::new(0, rows.start), iter);
781 it.set_screen_offset(screen_offset);
782 it.set_screen_width(screen_width);
783 it.set_tabs(self.masked.tab_width());
784 it.set_show_ctrl(self.masked.glyph_ctrl());
785 it.set_line_break(self.masked.glyph_line_break());
786 Ok(it)
787 }
788
789 #[inline]
795 pub(crate) fn glyphs2(
796 &self,
797 left_margin: upos_type,
798 right_margin: upos_type,
799 compact: bool,
800 ) -> Result<Box<dyn Iterator<Item = Glyph2<'_>> + '_>, TextError> {
801 let grapheme_iter = self
802 .masked
803 .graphemes(TextRange::new((0, 0), (0, 1)), TextPosition::new(0, 0))?;
804 let mask_iter = self.mask.iter();
805
806 let iter = MaskedGraphemes {
807 iter_str: grapheme_iter,
808 iter_mask: mask_iter,
809 compact,
810 sym_neg: self.neg_sym().to_string(),
811 sym_dec: self.dec_sep().to_string(),
812 sym_grp: self.grp_sep().to_string(),
813 sym_pos: self.pos_sym().to_string(),
814 byte_pos: 0,
815 };
816
817 let mut it = GlyphIter2::new(TextPosition::new(0, 0), 0, iter, Default::default());
818 it.set_tabs(self.masked.tab_width() as upos_type);
819 it.set_show_ctrl(self.masked.glyph_ctrl());
820 it.set_lf_breaks(self.masked.glyph_line_break());
821 it.set_text_wrap(TextWrap2::Shift);
822 it.set_left_margin(left_margin);
823 it.set_right_margin(right_margin);
824 it.set_word_margin(right_margin);
825 it.prepare()?;
826 Ok(Box::new(it))
827 }
828
829 #[inline]
831 pub fn grapheme_at(&self, pos: upos_type) -> Result<Option<Grapheme<'_>>, TextError> {
832 self.masked.grapheme_at(TextPosition::new(pos, 0))
833 }
834
835 #[inline]
837 pub fn text_graphemes(
838 &self,
839 pos: upos_type,
840 ) -> Result<impl Cursor<Item = Grapheme<'_>>, TextError> {
841 self.masked.text_graphemes(TextPosition::new(pos, 0))
842 }
843
844 #[inline]
846 pub fn graphemes(
847 &self,
848 range: Range<upos_type>,
849 pos: upos_type,
850 ) -> Result<impl Cursor<Item = Grapheme<'_>>, TextError> {
851 self.masked.graphemes(
852 TextRange::new((range.start, 0), (range.end, 0)),
853 TextPosition::new(pos, 0),
854 )
855 }
856
857 #[inline]
858 pub fn line_width(&self) -> upos_type {
859 self.masked.line_width(0).expect("valid_row")
860 }
861}
862
863#[derive(Debug, Clone)]
864struct MaskedGraphemes<'a> {
865 iter_str: StrGraphemes<'a>,
866 iter_mask: slice::Iter<'a, MaskToken>,
867
868 compact: bool,
869 sym_neg: String,
870 sym_dec: String,
871 sym_grp: String,
872 sym_pos: String,
873
874 byte_pos: usize,
875}
876
877impl<'a> Iterator for MaskedGraphemes<'a> {
878 type Item = Grapheme<'a>;
879
880 fn next(&mut self) -> Option<Self::Item> {
881 loop {
882 let g = self.iter_str.next();
883 let t = self.iter_mask.next();
884
885 let (Some(g), Some(t)) = (g, t) else {
886 return None;
887 };
888
889 self.byte_pos = g.text_bytes().end;
890
891 let r = match (self.compact, &t.right, g.grapheme()) {
892 (true, Mask::Numeric(_), "-") => Some(Grapheme::new(
893 Cow::Owned(self.sym_neg.clone()),
894 g.text_bytes(),
895 )),
896 (true, Mask::DecimalSep, ".") => Some(Grapheme::new(
897 Cow::Owned(self.sym_dec.clone()),
898 g.text_bytes(),
899 )),
900 (true, Mask::GroupingSep, ",") => Some(Grapheme::new(
901 Cow::Owned(self.sym_grp.clone()),
902 g.text_bytes(),
903 )),
904 (true, Mask::GroupingSep, "-") => Some(Grapheme::new(
905 Cow::Owned(self.sym_neg.clone()),
906 g.text_bytes(),
907 )),
908 (true, Mask::Sign, "-") => Some(Grapheme::new(
909 Cow::Owned(self.sym_neg.clone()),
910 g.text_bytes(),
911 )),
912
913 (true, Mask::Numeric(_), " ") => None,
914 (true, Mask::Digit(_), " ") => None,
915 (true, Mask::DecimalSep, " ") => None,
916 (true, Mask::GroupingSep, " ") => None,
917 (true, Mask::Sign, _) => {
918 if self.sym_pos != " " {
919 Some(Grapheme::new(
920 Cow::Owned(self.sym_pos.clone()),
921 g.text_bytes(),
922 ))
923 } else {
924 None
925 }
926 }
927 (true, Mask::Hex, " ") => None,
928 (true, Mask::Oct, " ") => None,
929 (true, Mask::Dec, " ") => None,
930
931 (false, Mask::Numeric(_), "-") => Some(Grapheme::new(
932 Cow::Owned(self.sym_neg.clone()),
933 g.text_bytes(),
934 )),
935 (false, Mask::DecimalSep, ".") => Some(Grapheme::new(
936 Cow::Owned(self.sym_dec.clone()),
937 g.text_bytes(),
938 )),
939 (false, Mask::GroupingSep, ",") => Some(Grapheme::new(
940 Cow::Owned(self.sym_grp.clone()),
941 g.text_bytes(),
942 )),
943 (false, Mask::GroupingSep, "-") => Some(Grapheme::new(
944 Cow::Owned(self.sym_neg.clone()),
945 g.text_bytes(),
946 )),
947 (false, Mask::Sign, "-") => Some(Grapheme::new(
948 Cow::Owned(self.sym_neg.clone()),
949 g.text_bytes(),
950 )),
951 (false, Mask::Sign, _) => Some(Grapheme::new(
952 Cow::Owned(self.sym_pos.clone()),
953 g.text_bytes(),
954 )),
955
956 (_, _, _) => Some(g),
957 };
958 if r.is_some() {
959 break r;
960 }
961 }
962 }
963}
964
965impl<'a> SkipLine for MaskedGraphemes<'a> {
966 fn skip_line(&mut self) -> Result<(), TextError> {
967 for _ in self.iter_str.by_ref() {}
969 for _ in self.iter_mask.by_ref() {}
970 Ok(())
971 }
972
973 fn skip_to(&mut self, byte_pos: usize) -> Result<(), TextError> {
974 if byte_pos > self.byte_pos {
975 Err(TextError::ByteIndexOutOfBounds(byte_pos, self.byte_pos))
976 } else if byte_pos == self.byte_pos {
977 Ok(())
978 } else {
979 for g in self.iter_str.by_ref() {
980 _ = self.iter_mask.next();
981
982 if byte_pos == g.text_bytes().end {
983 return Ok(());
984 } else if byte_pos < g.text_bytes().end {
985 return Err(TextError::ByteIndexNotCharBoundary(byte_pos));
986 }
987 }
988 Err(TextError::ByteIndexOutOfBounds(byte_pos, byte_pos))
989 }
990 }
991}
992
993impl MaskedCore {
994 #[inline]
996 fn default_value(&self) -> String {
997 MaskToken::empty_section(&self.mask)
998 }
999}
1000
1001impl MaskedCore {
1002 #[inline]
1005 pub fn clear(&mut self) {
1006 self.masked
1007 .set_text(TextString::new_string(self.default_value()));
1008 self.set_default_cursor();
1009 }
1010
1011 pub fn text(&self) -> &str {
1013 self.masked.text().as_str()
1014 }
1015
1016 #[allow(clippy::comparison_chain)]
1021 pub fn set_text<S: Into<String>>(&mut self, s: S) {
1022 let mut text = s.into();
1023 while text.graphemes(true).count() > self.mask.len().saturating_sub(1) {
1024 text.pop();
1025 }
1026 while text.graphemes(true).count() < self.mask.len().saturating_sub(1) {
1027 text.push(' ');
1028 }
1029 let len = text.graphemes(true).count();
1030
1031 assert_eq!(len, self.mask.len().saturating_sub(1));
1032
1033 self.masked.set_text(TextString::new_string(text));
1034 }
1035
1036 #[allow(clippy::if_same_then_else)]
1039 pub fn advance_cursor(&mut self, c: char) -> bool {
1040 if self.mask.is_empty() {
1041 return false;
1042 }
1043
1044 let mask_c = &self.mask[self.masked.cursor().x as usize];
1045
1046 let mut new_cursor = self.masked.cursor().x;
1047
1048 loop {
1049 let mask = &self.mask[new_cursor as usize];
1050
1051 if self.can_insert_integer_left(mask, new_cursor, c) {
1052 break;
1055 } else if self.can_insert_integer(mask, new_cursor, c) {
1056 break;
1059 } else if self.can_insert_sign(mask, new_cursor, c) {
1060 break;
1062 } else if self.can_insert_decimal_sep(mask, c) {
1063 break;
1065 } else if mask.right == Mask::GroupingSep {
1066 new_cursor += 1;
1068 } else if self.can_insert_separator(mask, c) {
1069 break;
1070 } else if self.can_move_left_in_fraction(mask_c, mask, new_cursor, c) {
1071 new_cursor -= 1;
1073 } else if self.can_insert_fraction(mask_c, mask, c) {
1074 break;
1075 } else if self.can_insert_other(mask, c) {
1076 break;
1077 } else if mask.right == Mask::None {
1078 new_cursor = self.masked.cursor().x;
1080 break;
1081 } else {
1082 new_cursor += 1;
1083 }
1084 }
1085
1086 self.masked
1087 .set_cursor(TextPosition::new(new_cursor, 0), false)
1088 }
1089
1090 fn is_valid_char(&self, mask: &Mask, c: char) -> bool {
1092 match mask {
1093 Mask::Digit0(_) => c.is_ascii_digit(),
1094 Mask::Digit(_) => c.is_ascii_digit() || c == ' ',
1095 Mask::Numeric(_) => c.is_ascii_digit() || c == self.neg_sym() || c == '-',
1096 Mask::DecimalSep => c == self.dec_sep(),
1097 Mask::GroupingSep => false,
1098 Mask::Sign => c == self.neg_sym() || c == '-',
1099 Mask::Plus => c == self.neg_sym() || c == '-',
1100 Mask::Hex0 => c.is_ascii_hexdigit(),
1101 Mask::Hex => c.is_ascii_hexdigit() || c == ' ',
1102 Mask::Oct0 => c.is_digit(8),
1103 Mask::Oct => c.is_digit(8) || c == ' ',
1104 Mask::Dec0 => c.is_ascii_digit(),
1105 Mask::Dec => c.is_ascii_digit() || c == ' ',
1106 Mask::Letter => c.is_alphabetic(),
1107 Mask::LetterOrDigit => c.is_alphanumeric(),
1108 Mask::LetterDigitSpace => c.is_alphanumeric() || c == ' ',
1109 Mask::AnyChar => true,
1110 Mask::Separator(sep) => {
1111 if c == '.' || c == ',' {
1113 true
1114 } else if let Some(sepc) = sep.chars().next() {
1115 sepc == c
1117 } else {
1118 false
1119 }
1120 }
1121 Mask::None => false,
1122 }
1123 }
1124
1125 #[inline]
1127 fn can_insert_other(&self, mask: &MaskToken, c: char) -> bool {
1128 match mask.right {
1129 Mask::Hex0
1130 | Mask::Hex
1131 | Mask::Oct0
1132 | Mask::Oct
1133 | Mask::Dec0
1134 | Mask::Dec
1135 | Mask::Letter
1136 | Mask::LetterOrDigit
1137 | Mask::LetterDigitSpace
1138 | Mask::AnyChar => self.is_valid_char(&mask.right, c),
1139 _ => false,
1140 }
1141 }
1142
1143 #[inline]
1145 fn can_insert_fraction(&self, mask_c: &MaskToken, mask: &MaskToken, c: char) -> bool {
1146 if !mask.right.is_fraction() {
1147 return false;
1148 }
1149 if !self.is_valid_char(&mask.right, c) {
1150 return false;
1151 }
1152 if mask_c.is_integer_part() {
1154 return false;
1155 }
1156
1157 true
1158 }
1159
1160 #[inline]
1164 fn can_move_left_in_fraction(
1165 &self,
1166 mask_c: &MaskToken,
1167 mask: &MaskToken,
1168 new_cursor: upos_type,
1169 c: char,
1170 ) -> bool {
1171 if !mask.peek_left.is_fraction() {
1172 return false;
1173 }
1174 if !self.is_valid_char(&mask.peek_left, c) {
1175 return false;
1176 }
1177 if mask_c.is_integer_part() {
1179 return false;
1180 }
1181
1182 let gl = self
1183 .masked
1184 .grapheme_at(TextPosition::new(new_cursor - 1, 0))
1185 .expect("valid_position")
1186 .expect("grapheme");
1187
1188 if gl != " " {
1190 return false;
1191 }
1192
1193 true
1194 }
1195
1196 #[inline]
1198 fn can_insert_sign<'a>(
1199 &'a self,
1200 mut mask: &'a MaskToken,
1201 new_cursor: upos_type,
1202 c: char,
1203 ) -> bool {
1204 if !self.is_valid_char(&Mask::Sign, c) {
1205 return false;
1206 }
1207 if mask.peek_left.is_number() && (mask.right.is_ltor() || mask.right.is_none()) {
1209 mask = &self.mask[new_cursor as usize - 1];
1210 }
1211 if !mask.right.is_number() {
1212 return false;
1213 }
1214
1215 for i in mask.sec_start..mask.sec_end {
1217 let t = &self.mask[i as usize];
1218 match t.right {
1219 Mask::Plus => return true,
1220 Mask::Sign => return true,
1221 Mask::Numeric(EditDirection::Rtol) => {
1222 let gi = self
1225 .masked
1226 .grapheme_at(TextPosition::new(i, 0))
1227 .expect("valid_position")
1228 .expect("grapheme");
1229
1230 return t.right.can_drop(gi.grapheme()) || gi == "-";
1231 }
1232 _ => {}
1233 }
1234 }
1235
1236 false
1237 }
1238
1239 #[inline]
1241 fn can_insert_integer(&self, mask: &MaskToken, new_cursor: upos_type, c: char) -> bool {
1242 if !mask.right.is_rtol() {
1243 return false;
1244 }
1245
1246 if !self.is_valid_char(&mask.right, c) {
1247 return false;
1248 }
1249
1250 let g = self
1251 .masked
1252 .grapheme_at(TextPosition::new(new_cursor, 0))
1253 .expect("valid_position")
1254 .expect("grapheme");
1255 if mask.right.can_drop(g.grapheme()) {
1256 return false;
1257 }
1258 if g == "-" {
1259 return false;
1260 }
1261
1262 true
1263 }
1264
1265 #[inline]
1267 fn can_insert_separator(&self, mask: &MaskToken, c: char) -> bool {
1268 if !matches!(mask.right, Mask::Separator(_)) {
1269 return false;
1270 }
1271 if !self.is_valid_char(&mask.right, c) {
1272 return false;
1273 }
1274 true
1275 }
1276
1277 #[inline]
1279 fn can_insert_decimal_sep(&self, mask: &MaskToken, c: char) -> bool {
1280 if mask.right != Mask::DecimalSep {
1281 return false;
1282 }
1283 if !self.is_valid_char(&mask.right, c) {
1284 return false;
1285 }
1286 true
1287 }
1288
1289 #[inline]
1291 fn can_insert_integer_left(&self, mask: &MaskToken, new_cursor: upos_type, c: char) -> bool {
1292 if !mask.peek_left.is_rtol() {
1293 return false;
1294 }
1295 if !mask.right.is_ltor() && !mask.right.is_none() {
1296 return false;
1297 }
1298
1299 let left = &self.mask[new_cursor as usize - 1];
1300 if !self.is_valid_char(&left.right, c) {
1301 return false;
1302 }
1303
1304 let mask0 = &self.mask[left.sub_start as usize];
1305 let g0 = self
1306 .masked
1307 .grapheme_at(TextPosition::new(left.sub_start, 0))
1308 .expect("valid_position")
1309 .expect("grapheme");
1310 if !mask0.right.can_drop(g0.grapheme()) {
1311 return false;
1312 }
1313
1314 true
1315 }
1316
1317 pub fn insert_char(&mut self, c: char) -> bool {
1323 if self.mask.is_empty() {
1324 return false;
1325 }
1326
1327 let cursor = self.masked.cursor();
1328
1329 {
1331 let mask = &self.mask[cursor.x as usize];
1332 if mask.right.is_number() && self.can_insert_sign(mask, cursor.x, c) {
1333 if self.insert_sign(c) {
1334 return true;
1335 }
1336 }
1337 }
1338 {
1339 let mask = &self.mask[cursor.x as usize];
1340 if mask.peek_left.is_number() && (mask.right.is_ltor() || mask.right.is_none()) {
1341 let left = &self.mask[cursor.x as usize - 1];
1342 if self.can_insert_sign(left, cursor.x, c) {
1343 if self.insert_sign(c) {
1344 return true;
1345 }
1346 }
1347 }
1348 }
1349 {
1350 let mask = &self.mask[cursor.x as usize];
1351 if mask.right.is_rtol() {
1352 if self.insert_rtol(c) {
1353 return true;
1354 }
1355 }
1356 }
1357 {
1358 let mask = &self.mask[cursor.x as usize];
1359 if mask.peek_left.is_rtol() && (mask.right.is_ltor() || mask.right.is_none()) {
1360 if self.insert_rtol(c) {
1361 return true;
1362 }
1363 }
1364 }
1365 {
1366 let mask = &self.mask[cursor.x as usize];
1367 if mask.right.is_ltor() {
1368 if self.insert_ltor(c) {
1369 #[allow(clippy::needless_return)]
1370 return true;
1371 }
1372 }
1373 }
1374
1375 false
1376 }
1377
1378 fn insert_ltor(&mut self, c: char) -> bool {
1380 let cursor = self.masked.cursor();
1381
1382 let mask = &self.mask[cursor.x as usize];
1383 let mask9 = &self.mask[mask.sub_end as usize - 1];
1384
1385 let g = self
1387 .masked
1388 .grapheme_at(cursor)
1389 .expect("valid_cursor")
1390 .expect("mask");
1391 if mask.right.is_fraction()
1392 && mask.right.can_overwrite_fraction(g.grapheme())
1393 && self.is_valid_char(&mask.right, c)
1394 {
1395 let frac_mask = &self.mask[cursor.x as usize + 1..mask.sub_end as usize];
1397 let frac_str = self
1398 .masked
1399 .str_slice(TextRange::new((cursor.x + 1, 0), (mask.sub_end, 0)))
1400 .expect("valid_range");
1401 if frac_str == MaskToken::empty_section(frac_mask) {
1402 self.masked.begin_undo_seq();
1403 self.masked
1404 .remove_char_range(TextRange::new(cursor, (cursor.x + 1, 0)))
1405 .expect("valid_cursor");
1406 self.masked.insert_char(cursor, c).expect("valid_cursor");
1407 self.masked.end_undo_seq();
1408 return true;
1409 }
1410 }
1411
1412 let g = self
1413 .masked
1414 .grapheme_at(cursor)
1415 .expect("valid_cursor")
1416 .expect("mask");
1417 if mask.right.can_overwrite(g.grapheme()) && self.is_valid_char(&mask.right, c) {
1418 if mask.right.is_separator() {
1419 self.masked.begin_undo_seq();
1420 let r = if let Some(next) = self.next_section_cursor(cursor.x) {
1421 self.masked.set_cursor(TextPosition::new(next, 0), false)
1422 } else {
1423 self.masked
1424 .set_cursor(TextPosition::new(self.line_width(), 0), false)
1425 };
1426 self.masked.end_undo_seq();
1427 return r;
1428 } else if mask.right == Mask::DecimalSep {
1429 self.masked.begin_undo_seq();
1430 self.masked
1431 .set_cursor(TextPosition::new(cursor.x + 1, 0), false);
1432 self.masked.end_undo_seq();
1433 return true;
1434 } else {
1435 self.masked.begin_undo_seq();
1436 self.masked
1437 .remove_char_range(TextRange::new(cursor, (cursor.x + 1, 0)))
1438 .expect("valid_cursor");
1439 self.masked.insert_char(cursor, c).expect("valid_cursor");
1440 self.masked.end_undo_seq();
1441 return true;
1442 }
1443 }
1444
1445 let g9 = self
1447 .masked
1448 .grapheme_at(TextPosition::new(mask.sub_end - 1, 0))
1449 .expect("valid_pos")
1450 .expect("mask");
1451 if mask9.right.can_drop(g9.grapheme()) && self.is_valid_char(&mask.right, c) {
1452 self.masked.begin_undo_seq();
1453 self.masked
1454 .remove_char_range(TextRange::new((mask.sub_end - 1, 0), (mask.sub_end, 0)))
1455 .expect("valid_range");
1456 self.masked.insert_char(cursor, c).expect("valid_cursor");
1457 self.masked.end_undo_seq();
1458 return true;
1459 }
1460 false
1461 }
1462
1463 fn insert_rtol(&mut self, c: char) -> bool {
1465 let cursor = self.masked.cursor();
1466
1467 let mut mask = &self.mask[cursor.x as usize];
1468
1469 if mask.peek_left.is_rtol() && (mask.right.is_ltor() || mask.right.is_none()) {
1471 mask = &self.mask[cursor.x as usize - 1];
1472 }
1473
1474 let mask0 = &self.mask[mask.sub_start as usize];
1475
1476 let g0 = self
1477 .masked
1478 .grapheme_at(TextPosition::new(mask.sub_start, 0))
1479 .expect("valid_pos")
1480 .expect("grapheme");
1481 if mask0.right.can_drop(g0.grapheme()) && self.is_valid_char(&mask.right, c) {
1482 self.masked.begin_undo_seq();
1483 self.masked
1484 .remove_char_range(TextRange::new((mask.sub_start, 0), (mask.sub_start + 1, 0)))
1485 .expect("valid_position");
1486 self.masked
1487 .insert_char(TextPosition::new(cursor.x - 1, 0), c)
1488 .expect("valid_position");
1489 Self::reformat(&mut self.masked, &self.mask, mask.sub_start..mask.sub_end);
1490 self.masked.end_undo_seq();
1491 return true;
1492 }
1493
1494 false
1495 }
1496
1497 #[allow(clippy::single_match)]
1499 fn insert_sign(&mut self, c: char) -> bool {
1500 let cursor = self.masked.cursor();
1501
1502 let mut mask = &self.mask[cursor.x as usize];
1503 if mask.peek_left.is_number() && (mask.right.is_ltor() || mask.right.is_none()) {
1505 mask = &self.mask[cursor.x as usize - 1];
1506 }
1507
1508 let idx = self.mask[mask.sec_start as usize..mask.sec_end as usize]
1510 .iter()
1511 .enumerate()
1512 .find(|(_, t)| matches!(t.right, Mask::Sign | Mask::Plus))
1513 .map(|(i, _)| mask.sec_start as usize + i);
1514
1515 let idx = if idx.is_none() {
1517 self.masked
1518 .graphemes(
1519 TextRange::new((mask.sec_start, 0), (mask.sec_end, 0)),
1520 TextPosition::new(mask.sec_start, 0),
1521 )
1522 .expect("valid_range")
1523 .enumerate()
1524 .find(|(_, g)| *g == "-" || *g == "+")
1525 .map(|(i, _)| mask.sec_start as usize + i)
1526 } else {
1527 idx
1528 };
1529
1530 let idx = if idx.is_none() {
1531 let mut idx = mask.sec_end - 1;
1533 'f: {
1534 while idx >= mask.sec_start {
1535 if self.mask[idx as usize].right == Mask::Numeric(EditDirection::Rtol) {
1536 let g = self
1537 .grapheme_at(idx)
1538 .expect("valid_position")
1539 .expect("grapheme");
1540
1541 if self.mask[idx as usize].right.can_drop(g.grapheme()) {
1542 break 'f Some(idx as usize);
1543 }
1544 }
1545 idx -= 1;
1546 }
1547 None
1548 }
1549 } else {
1550 idx
1551 };
1552
1553 if let Some(idx) = idx {
1554 let mask_sign = &self.mask[idx];
1555
1556 if c == self.neg_sym() || c == '-' {
1557 let g = self
1559 .masked
1560 .str_slice(TextRange::new(
1561 (idx as upos_type, 0),
1562 (idx as upos_type + 1, 0),
1563 ))
1564 .expect("valid_pos")
1565 .to_string();
1566
1567 self.masked.begin_undo_seq();
1568 self.masked
1569 .remove_char_range(TextRange::new(
1570 (idx as upos_type, 0),
1571 (idx as upos_type + 1, 0),
1572 ))
1573 .expect("valid_range");
1574
1575 let cc = match &mask_sign.right {
1576 Mask::Numeric(_) | Mask::Sign => {
1577 if g == "-" {
1578 ' '
1579 } else {
1580 '-'
1581 }
1582 }
1583 Mask::Plus => {
1584 if g == "-" {
1585 '+'
1586 } else {
1587 '-'
1588 }
1589 }
1590 _ => unreachable!(),
1591 };
1592
1593 self.masked
1594 .insert_char(TextPosition::new(idx as upos_type, 0), cc)
1595 .expect("valid_range");
1596 self.set_cursor(cursor.x, false);
1597 self.masked.end_undo_seq();
1598 true
1599 } else {
1600 false
1601 }
1602 } else {
1603 false
1604 }
1605 }
1606
1607 pub fn remove_prev(&mut self) {
1609 let cursor = self.masked.cursor();
1610
1611 if cursor.x == 0 {
1612 return;
1613 }
1614
1615 let left = &self.mask[cursor.x as usize - 1];
1616
1617 if left.right.is_rtol() {
1618 let sec_empty = if left.right.is_rtol() {
1620 let sec_str = self
1621 .masked
1622 .str_slice(TextRange::new((left.sub_start, 0), (left.sub_end, 0)))
1623 .expect("valid_range");
1624 let sec_mask = &self.mask[left.sub_start as usize..left.sub_end as usize];
1625 sec_str == MaskToken::empty_section(sec_mask)
1626 } else {
1627 false
1628 };
1629
1630 let l0 = &self.mask[left.sub_start as usize];
1631
1632 self.masked.begin_undo_seq();
1633 self.masked
1634 .remove_char_range(TextRange::new((cursor.x - 1, 0), cursor))
1635 .expect("valid_range");
1636 self.masked
1637 .insert_str(TextPosition::new(left.sub_start, 0), &l0.edit)
1638 .expect("valid_position");
1639 Self::reformat(&mut self.masked, &self.mask, left.sub_start..left.sub_end);
1640
1641 if sec_empty {
1645 self.masked
1646 .set_cursor(TextPosition::new(left.sub_start, 0), false);
1647 } else {
1648 }
1650
1651 self.masked.end_undo_seq();
1652 } else if left.right.is_ltor() {
1653 let l9 = &self.mask[left.sub_end as usize - 1];
1654
1655 self.masked.begin_undo_seq();
1656 self.masked
1657 .remove_char_range(TextRange::new((cursor.x - 1, 0), cursor))
1658 .expect("valid_range");
1659 self.masked
1660 .insert_str(TextPosition::new(left.sub_end - 1, 0), &l9.edit)
1661 .expect("valid_position");
1662
1663 Self::reformat(&mut self.masked, &self.mask, left.sub_start..left.sub_end);
1664
1665 self.masked
1666 .set_cursor(TextPosition::new(cursor.x - 1, 0), false);
1667
1668 self.masked.end_undo_seq();
1669 }
1670 }
1671
1672 pub fn remove_next(&mut self) {
1674 let cursor = self.masked.cursor();
1675
1676 if cursor.x as usize == self.mask.len() - 1 {
1677 return;
1678 }
1679
1680 let right = &self.mask[cursor.x as usize];
1681
1682 if right.right.is_rtol() {
1684 let l0 = &self.mask[right.sub_start as usize];
1685
1686 self.masked.begin_undo_seq();
1687 self.masked
1688 .remove_char_range(TextRange::new(cursor, (cursor.x + 1, 0)))
1689 .expect("valid_range");
1690 self.masked
1691 .insert_str(TextPosition::new(right.sub_start, 0), &l0.edit)
1692 .expect("valid_position");
1693 Self::reformat(&mut self.masked, &self.mask, right.sub_start..right.sub_end);
1694
1695 self.masked
1696 .set_cursor(TextPosition::new(cursor.x + 1, 0), false);
1697
1698 self.masked.end_undo_seq();
1699 } else if right.right.is_ltor() {
1700 let sec_str = self
1702 .masked
1703 .str_slice(TextRange::new((right.sub_start, 0), (right.sub_end, 0)))
1704 .expect("valid_range");
1705 let sec_mask = &self.mask[right.sub_start as usize..right.sub_end as usize];
1706 let sec_empty = sec_str == MaskToken::empty_section(sec_mask);
1707
1708 let l9 = &self.mask[right.sub_end as usize - 1];
1709
1710 self.masked.begin_undo_seq();
1711 self.masked
1712 .remove_char_range(TextRange::new(cursor, (cursor.x + 1, 0)))
1713 .expect("valid_range");
1714 self.masked
1715 .insert_str(TextPosition::new(right.sub_end - 1, 0), &l9.edit)
1716 .expect("valid_position");
1717
1718 Self::reformat(&mut self.masked, &self.mask, right.sub_start..right.sub_end);
1719
1720 if sec_empty {
1724 self.masked
1725 .set_cursor(TextPosition::new(right.sub_end, 0), false);
1726 } else {
1727 }
1729
1730 self.masked.end_undo_seq();
1731 }
1732 }
1733
1734 pub fn remove_range(&mut self, range: Range<upos_type>) -> Result<bool, TextError> {
1736 self.masked
1738 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))?;
1739
1740 if range.is_empty() {
1741 return Ok(false);
1742 }
1743
1744 let mask = &self.mask[range.start as usize];
1745 if range.start >= mask.sub_start && range.end <= mask.sub_end {
1746 if mask.right.is_rtol() {
1747 self.masked.begin_undo_seq();
1748 self.masked
1749 .remove_str_range(TextRange::new((range.start, 0), (range.end, 0)))
1750 .expect("valid_range");
1751 let fill_before =
1752 &self.mask[mask.sub_start as usize..mask.sub_start as usize + range.len()];
1753 self.masked
1754 .insert_str(
1755 TextPosition::new(mask.sub_start, 0),
1756 &MaskToken::empty_section(fill_before),
1757 )
1758 .expect("valid_range");
1759 Self::reformat(&mut self.masked, &self.mask, mask.sub_start..mask.sub_end);
1760 self.masked.end_undo_seq();
1761 } else if mask.right.is_ltor() {
1762 self.masked.begin_undo_seq();
1763 self.masked
1764 .remove_str_range(TextRange::new((range.start, 0), (range.end, 0)))
1765 .expect("valid_range");
1766 let fill_after =
1767 &self.mask[mask.sub_end as usize - range.len()..mask.sub_end as usize];
1768 self.masked
1769 .insert_str(
1770 TextPosition::new(mask.sub_end - range.len() as upos_type, 0),
1771 &MaskToken::empty_section(fill_after),
1772 )
1773 .expect("valid_range");
1774 Self::reformat(&mut self.masked, &self.mask, mask.sub_start..mask.sub_end);
1775 self.masked.end_undo_seq();
1776 }
1777
1778 return Ok(true);
1779 }
1780
1781 let mut pos = range.start;
1782 self.masked.begin_undo_seq();
1783 loop {
1784 let mask = &self.mask[pos as usize];
1785
1786 if mask.sub_start < range.start {
1787 if mask.right.is_rtol() {
1789 self.masked
1790 .remove_str_range(TextRange::new((range.start, 0), (mask.sub_end, 0)))
1791 .expect("valid_range");
1792
1793 let len = mask.sub_end - range.start;
1794 let fill_before =
1795 &self.mask[mask.sub_start as usize..(mask.sub_start + len) as usize];
1796 self.masked
1797 .insert_str(
1798 TextPosition::new(mask.sub_start, 0),
1799 &MaskToken::empty_section(fill_before),
1800 )
1801 .expect("valid_range");
1802
1803 Self::reformat(&mut self.masked, &self.mask, mask.sub_start..mask.sub_end);
1804
1805 pos = mask.sub_end;
1806 } else if mask.right.is_ltor() {
1807 self.masked
1808 .remove_str_range(TextRange::new((range.start, 0), (mask.sub_end, 0)))
1809 .expect("valid_range");
1810
1811 let fill_after = &self.mask[range.start as usize..mask.sub_end as usize];
1812 self.masked
1813 .insert_str(
1814 TextPosition::new(range.start, 0),
1815 &MaskToken::empty_section(fill_after),
1816 )
1817 .expect("valid_range");
1818
1819 Self::reformat(&mut self.masked, &self.mask, mask.sub_start..mask.sub_end);
1820
1821 pos = mask.sub_end;
1822 }
1823 } else if mask.sub_end > range.end {
1824 if mask.right.is_rtol() {
1826 self.masked
1827 .remove_str_range(TextRange::new((mask.sub_start, 0), (range.end, 0)))
1828 .expect("valid_range");
1829
1830 let fill_before = &self.mask[mask.sub_start as usize..range.end as usize];
1831 self.masked
1832 .insert_str(
1833 TextPosition::new(mask.sub_start, 0),
1834 &MaskToken::empty_section(fill_before),
1835 )
1836 .expect("valid_range");
1837
1838 Self::reformat(&mut self.masked, &self.mask, mask.sub_start..mask.sub_end);
1839 pos = mask.sub_end;
1840 } else if mask.right.is_ltor() {
1841 self.masked
1842 .remove_str_range(TextRange::new((mask.sub_start, 0), (range.end, 0)))
1843 .expect("valid_range");
1844
1845 let len = range.end - mask.sub_start;
1846 let fill_after =
1847 &self.mask[(mask.sub_end - len) as usize..mask.sub_end as usize];
1848 self.masked
1849 .insert_str(
1850 TextPosition::new(mask.sub_end - len, 0),
1851 &MaskToken::empty_section(fill_after),
1852 )
1853 .expect("valid_range");
1854
1855 pos = mask.sub_end;
1856 }
1857 } else {
1858 self.masked
1860 .remove_str_range(TextRange::new((mask.sub_start, 0), (mask.sub_end, 0)))
1861 .expect("valid_range");
1862
1863 let sec_range = &self.mask[mask.sub_start as usize..mask.sub_end as usize];
1864 self.masked
1865 .insert_str(
1866 TextPosition::new(mask.sub_start, 0),
1867 &MaskToken::empty_section(sec_range),
1868 )
1869 .expect("valid_range");
1870
1871 pos = mask.sub_end;
1873 }
1874
1875 if pos >= range.end {
1876 break;
1877 }
1878 }
1879 self.masked.end_undo_seq();
1880
1881 Ok(true)
1882 }
1883
1884 fn reformat(core: &mut TextCore<TextString>, mask: &[MaskToken], section: Range<upos_type>) {
1887 if mask[section.start as usize].right.is_rtol() {
1888 let cursor = core.cursor();
1889 let anchor = core.anchor();
1890
1891 let sec_str = core
1892 .str_slice(TextRange::new((section.start, 0), (section.end, 0)))
1893 .expect("valid_range");
1894
1895 let sym = NumberSymbols {
1897 decimal_sep: '.',
1898 decimal_grp: Some(','),
1899 negative_sym: '-',
1900 positive_sym: ' ',
1901 exponent_upper_sym: 'E',
1902 exponent_lower_sym: 'e',
1903 currency_sym: CurrencySym::new("$"),
1904 };
1905
1906 let mut clean = String::new();
1908 _ = clean_num(sec_str.as_ref(), &sym, &mut clean);
1909
1910 let mut tok = String::new();
1912 let submask = &mask[section.start as usize..section.end as usize];
1913 for t in submask {
1915 match &t.right {
1916 Mask::Digit0(_) => tok.push('0'),
1917 Mask::Digit(_) => tok.push('9'),
1918 Mask::Numeric(_) => tok.push('#'),
1919 Mask::DecimalSep => tok.push('.'),
1920 Mask::GroupingSep => tok.push(','),
1921 Mask::Sign => tok.push('-'),
1922 Mask::Plus => tok.push('+'),
1923 Mask::Separator(s) => {
1924 for c in s.chars() {
1925 tok.push('\\');
1926 tok.push(c);
1927 }
1928 }
1929 Mask::None => {}
1930 _ => unreachable!("invalid mask"),
1931 }
1932 }
1933
1934 let fmt = match NumberFormat::news(tok, sym) {
1935 Ok(v) => v,
1936 Err(_) => unreachable!("invalid mask"),
1937 };
1938 let mut out = String::new();
1939 match map_num::<_, false>(clean.as_str(), &fmt, fmt.sym(), &mut out) {
1940 Ok(_) => {}
1941 Err(_) => unreachable!("invalid mask"),
1942 }
1943
1944 core.remove_char_range(TextRange::new((section.start, 0), (section.end, 0)))
1945 .expect("valid_range");
1946 core.insert_str(TextPosition::new(section.start, 0), &out)
1947 .expect("valid_position");
1948
1949 core.set_cursor(anchor, false);
1951 core.set_cursor(cursor, true);
1952 } else if mask[section.start as usize].right.is_ltor() {
1953 let cursor = core.cursor();
1954 let anchor = core.anchor();
1955
1956 let sec_str = core
1957 .str_slice(TextRange::new((section.start, 0), (section.end, 0)))
1958 .expect("valid_range");
1959 let sec_mask = &mask[section.start as usize..section.end as usize];
1960 let mut str_new = String::new();
1961 for (g, t) in sec_str.graphemes(true).zip(sec_mask.iter()) {
1962 match t.right {
1963 Mask::Digit0(_) | Mask::Hex0 | Mask::Oct0 | Mask::Dec0 => {
1964 if g == " " {
1965 str_new.push('0');
1966 } else {
1967 str_new.push_str(g);
1968 }
1969 }
1970 _ => {
1971 str_new.push_str(g);
1972 }
1973 }
1974 }
1975
1976 if sec_str != str_new {
1977 core.remove_char_range(TextRange::new((section.start, 0), (section.end, 0)))
1978 .expect("valid_range");
1979 core.insert_str(TextPosition::new(section.start, 0), &str_new)
1980 .expect("valid_position");
1981
1982 core.set_cursor(anchor, false);
1984 core.set_cursor(cursor, true);
1985 }
1986 }
1987 }
1988}
1989
1990mod mask {
1991 use crate::upos_type;
1992 use std::fmt;
1993 use std::fmt::{Debug, Display, Formatter};
1994
1995 #[derive(Clone, Copy, PartialEq, Eq)]
1998 pub(super) enum EditDirection {
1999 Ltor,
2000 Rtol,
2001 }
2002
2003 #[allow(variant_size_differences)]
2005 #[derive(Clone, PartialEq, Eq, Default)]
2006 #[non_exhaustive]
2007 pub(super) enum Mask {
2008 Digit0(EditDirection),
2010 Digit(EditDirection),
2012 Numeric(EditDirection),
2014 DecimalSep,
2015 GroupingSep,
2016 Sign,
2017 Plus,
2018 Hex0,
2019 Hex,
2020 Oct0,
2021 Oct,
2022 Dec0,
2023 Dec,
2024 Letter,
2025 LetterOrDigit,
2026 LetterDigitSpace,
2027 AnyChar,
2028 Separator(Box<str>),
2029 #[default]
2030 None,
2031 }
2032
2033 #[derive(Clone, PartialEq, Eq)]
2044 pub(super) struct MaskToken {
2045 pub sec_id: u16,
2046 pub sec_start: upos_type,
2048 pub sec_end: upos_type,
2050 pub sub_start: upos_type,
2052 pub sub_end: upos_type,
2054
2055 pub peek_left: Mask,
2057 pub right: Mask,
2059
2060 pub edit: Box<str>,
2062 }
2063
2064 impl Debug for EditDirection {
2065 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2066 write!(
2067 f,
2068 "{}",
2069 match self {
2070 EditDirection::Ltor => ">",
2071 EditDirection::Rtol => "<",
2072 }
2073 )
2074 }
2075 }
2076
2077 impl Display for Mask {
2078 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2079 let s = match self {
2080 Mask::Digit0(_) => "0",
2081 Mask::Digit(_) => "9",
2082 Mask::Numeric(_) => "#",
2083 Mask::DecimalSep => ".",
2084 Mask::GroupingSep => ",",
2085 Mask::Sign => "-",
2086 Mask::Plus => "+",
2087 Mask::Hex0 => "H",
2088 Mask::Hex => "h",
2089 Mask::Oct0 => "O",
2090 Mask::Oct => "o",
2091 Mask::Dec0 => "D",
2092 Mask::Dec => "d",
2093 Mask::Letter => "l",
2094 Mask::LetterOrDigit => "a",
2095 Mask::LetterDigitSpace => "c",
2096 Mask::AnyChar => "_",
2097 Mask::Separator(s) => {
2098 write!(f, "\\")?;
2099 s
2100 }
2101 Mask::None => "",
2102 };
2103 write!(f, "{}", s)
2104 }
2105 }
2106
2107 impl Debug for Mask {
2108 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2109 match self {
2110 Mask::Digit0(d) => {
2111 write!(f, "{:?}0", d)
2112 }
2113 Mask::Digit(d) => {
2114 write!(f, "{:?}9", d)
2115 }
2116 Mask::Numeric(d) => {
2117 write!(f, "{:?}#", d)
2118 }
2119 Mask::DecimalSep => write!(f, "."),
2120 Mask::GroupingSep => write!(f, ","),
2121 Mask::Sign => write!(f, "-"),
2122 Mask::Plus => write!(f, "+"),
2123 Mask::Hex0 => write!(f, "H"),
2124 Mask::Hex => write!(f, "h"),
2125 Mask::Oct0 => write!(f, "O"),
2126 Mask::Oct => write!(f, "o"),
2127 Mask::Dec0 => write!(f, "D"),
2128 Mask::Dec => write!(f, "d"),
2129 Mask::Letter => write!(f, "l"),
2130 Mask::LetterOrDigit => write!(f, "a"),
2131 Mask::LetterDigitSpace => write!(f, "c"),
2132 Mask::AnyChar => write!(f, "_"),
2133 Mask::Separator(s) => {
2134 write!(f, "\\")?;
2135 write!(f, "{}", s)
2136 }
2137 Mask::None => write!(f, ""),
2138 }
2139 }
2140 }
2141
2142 impl EditDirection {
2143 pub(super) fn is_ltor(&self) -> bool {
2144 *self == EditDirection::Ltor
2145 }
2146
2147 pub(super) fn is_rtol(&self) -> bool {
2148 *self == EditDirection::Rtol
2149 }
2150 }
2151
2152 impl Mask {
2153 pub(super) fn is_none(&self) -> bool {
2156 *self == Mask::None
2157 }
2158
2159 #[inline]
2161 pub(super) fn is_ltor(&self) -> bool {
2162 match self {
2163 Mask::Digit0(d) => d.is_ltor(),
2164 Mask::Digit(d) => d.is_ltor(),
2165 Mask::Numeric(d) => d.is_ltor(),
2166 Mask::GroupingSep => false,
2167 Mask::Sign => false,
2168 Mask::Plus => false,
2169 Mask::DecimalSep => true,
2170 Mask::Hex0 => true,
2171 Mask::Hex => true,
2172 Mask::Oct0 => true,
2173 Mask::Oct => true,
2174 Mask::Dec0 => true,
2175 Mask::Dec => true,
2176 Mask::Letter => true,
2177 Mask::LetterOrDigit => true,
2178 Mask::LetterDigitSpace => true,
2179 Mask::AnyChar => true,
2180 Mask::Separator(_) => true,
2181 Mask::None => false,
2182 }
2183 }
2184
2185 #[inline]
2187 pub(super) fn is_rtol(&self) -> bool {
2188 match self {
2189 Mask::Digit0(d) => d.is_rtol(),
2190 Mask::Digit(d) => d.is_rtol(),
2191 Mask::Numeric(d) => d.is_rtol(),
2192 Mask::GroupingSep => true,
2193 Mask::Sign => true,
2194 Mask::Plus => true,
2195 Mask::DecimalSep => false,
2196 Mask::Hex0 => false,
2197 Mask::Hex => false,
2198 Mask::Oct0 => false,
2199 Mask::Oct => false,
2200 Mask::Dec0 => false,
2201 Mask::Dec => false,
2202 Mask::Letter => false,
2203 Mask::LetterOrDigit => false,
2204 Mask::LetterDigitSpace => false,
2205 Mask::AnyChar => false,
2206 Mask::Separator(_) => false,
2207 Mask::None => false,
2208 }
2209 }
2210
2211 #[inline]
2213 pub(super) fn is_number(&self) -> bool {
2214 match self {
2215 Mask::Digit0(_)
2216 | Mask::Digit(_)
2217 | Mask::Numeric(_)
2218 | Mask::DecimalSep
2219 | Mask::GroupingSep
2220 | Mask::Sign
2221 | Mask::Plus => true,
2222 Mask::None => false,
2223 _ => false,
2224 }
2225 }
2226
2227 #[inline]
2229 pub(super) fn is_separator(&self) -> bool {
2230 match self {
2231 Mask::Separator(_) => true,
2232 Mask::None => false,
2233 _ => false,
2234 }
2235 }
2236
2237 #[inline]
2238 pub(super) fn is_fraction(&self) -> bool {
2239 match self {
2240 Mask::Digit0(d) | Mask::Digit(d) | Mask::Numeric(d) => d.is_ltor(),
2241 Mask::None => false,
2242 _ => false,
2243 }
2244 }
2245
2246 #[inline]
2248 pub(super) fn sub_section(&self) -> u8 {
2249 match self {
2250 Mask::Digit0(_) => 0,
2251 Mask::Digit(_) => 0,
2252 Mask::Numeric(_) => 0,
2253 Mask::GroupingSep => 0,
2254
2255 Mask::Sign => 1,
2256
2257 Mask::Plus => 2,
2258
2259 Mask::DecimalSep => 3,
2260
2261 Mask::Hex0 => 4,
2262 Mask::Hex => 4,
2263
2264 Mask::Oct0 => 5,
2265 Mask::Oct => 5,
2266
2267 Mask::Dec0 => 6,
2268 Mask::Dec => 6,
2269
2270 Mask::Letter => 7,
2271 Mask::LetterOrDigit => 8,
2272 Mask::LetterDigitSpace => 9,
2273 Mask::AnyChar => 10,
2274
2275 Mask::Separator(_) => 11,
2276
2277 Mask::None => 12,
2278 }
2279 }
2280
2281 #[inline]
2283 pub(super) fn section(&self) -> u8 {
2284 match self {
2285 Mask::Digit0(_) => 0,
2286 Mask::Digit(_) => 0,
2287 Mask::Numeric(_) => 0,
2288 Mask::GroupingSep => 0,
2289 Mask::Sign => 0,
2290 Mask::Plus => 0,
2291 Mask::DecimalSep => 0,
2292
2293 Mask::Hex0 => 1,
2294 Mask::Hex => 1,
2295 Mask::Oct0 => 1,
2296 Mask::Oct => 1,
2297 Mask::Dec0 => 1,
2298 Mask::Dec => 1,
2299 Mask::Letter => 1,
2300 Mask::LetterOrDigit => 1,
2301 Mask::LetterDigitSpace => 1,
2302 Mask::AnyChar => 1,
2303
2304 Mask::Separator(_) => 2,
2305 Mask::None => 3,
2306 }
2307 }
2308
2309 #[inline]
2311 pub(super) fn can_overwrite_fraction(&self, c: &str) -> bool {
2312 match self {
2313 Mask::Digit0(_) => c == "0",
2314 Mask::Digit(_) | Mask::Numeric(_) => c == " ",
2315 Mask::DecimalSep => false,
2316 Mask::GroupingSep => false,
2317 Mask::Sign => false,
2318 Mask::Plus => false,
2319 Mask::Hex0 => false,
2320 Mask::Hex => false,
2321 Mask::Oct0 => false,
2322 Mask::Oct => false,
2323 Mask::Dec0 => false,
2324 Mask::Dec => false,
2325 Mask::Letter => false,
2326 Mask::LetterOrDigit => false,
2327 Mask::LetterDigitSpace => false,
2328 Mask::AnyChar => false,
2329 Mask::Separator(_) => false,
2330 Mask::None => false,
2331 }
2332 }
2333
2334 #[inline]
2336 pub(super) fn can_overwrite(&self, c: &str) -> bool {
2337 match self {
2338 Mask::Digit0(_) | Mask::Digit(_) | Mask::Numeric(_) => false,
2339 Mask::DecimalSep => "." == c,
2340 Mask::GroupingSep => false,
2341 Mask::Sign => "-" == c || " " == c,
2342 Mask::Plus => "-" == c || "+" == c || " " == c,
2343 Mask::Hex0 => c == "0",
2344 Mask::Hex => false,
2345 Mask::Oct0 => c == "0",
2346 Mask::Oct => false,
2347 Mask::Dec0 => c == "0",
2348 Mask::Dec => false,
2349 Mask::Letter => false,
2350 Mask::LetterOrDigit => false,
2351 Mask::LetterDigitSpace => false,
2352 Mask::AnyChar => false,
2353 Mask::Separator(sep) => sep.as_ref() == c,
2354 Mask::None => false,
2355 }
2356 }
2357
2358 #[inline]
2360 pub(super) fn can_drop(&self, c: &str) -> bool {
2361 match self {
2362 Mask::Digit0(_) => c == "0",
2363 Mask::Digit(_) => c == " ",
2364 Mask::Numeric(_) => c == " ",
2365 Mask::DecimalSep => false,
2366 Mask::Sign => false,
2367 Mask::Plus => false,
2368 Mask::GroupingSep => true,
2369 Mask::Hex0 => c == "0",
2370 Mask::Hex => c == " ",
2371 Mask::Oct0 => c == "0",
2372 Mask::Oct => c == " ",
2373 Mask::Dec0 => c == "0",
2374 Mask::Dec => c == " ",
2375 Mask::Letter => c == " ",
2376 Mask::LetterOrDigit => c == " ",
2377 Mask::LetterDigitSpace => c == " ",
2378 Mask::AnyChar => c == " ",
2379 Mask::Separator(_sep) => false,
2380 Mask::None => false,
2381 }
2382 }
2383
2384 #[inline]
2386 pub(super) fn edit_value(&self) -> &str {
2387 match self {
2388 Mask::Digit0(_) => "0",
2389 Mask::Digit(_) => " ",
2390 Mask::Numeric(_) => " ",
2391 Mask::DecimalSep => ".",
2392 Mask::GroupingSep => " ", Mask::Sign => " ",
2394 Mask::Plus => "+",
2395 Mask::Hex0 => "0",
2396 Mask::Hex => " ",
2397 Mask::Oct0 => "0",
2398 Mask::Oct => " ",
2399 Mask::Dec0 => "0",
2400 Mask::Dec => " ",
2401 Mask::Letter => " ",
2402 Mask::LetterOrDigit => " ",
2403 Mask::LetterDigitSpace => " ",
2404 Mask::AnyChar => " ",
2405 Mask::Separator(g) => g.as_ref(),
2406 Mask::None => "",
2407 }
2408 }
2409 }
2410
2411 impl Debug for MaskToken {
2412 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2413 write!(
2414 f,
2415 "Mask #{}:{}-{} {:?} | {:?}",
2416 self.sec_id, self.sub_start, self.sub_end, self.peek_left, self.right
2417 )
2418 }
2419 }
2420
2421 impl MaskToken {
2422 #[inline]
2424 pub(super) fn is_integer_part(&self) -> bool {
2425 self.peek_left.is_rtol() || self.peek_left.is_none() && self.right.is_rtol()
2426 }
2427
2428 pub(super) fn empty_section(mask: &[MaskToken]) -> String {
2430 let mut buf = String::new();
2431 for m in mask {
2432 buf.push_str(&m.edit);
2433 }
2434 buf
2435 }
2436 }
2437}