tabled/settings/formatting/charset.rs
1use std::borrow::Cow;
2
3use crate::{
4 grid::config::{Entity, Position},
5 grid::records::{ExactRecords, PeekableRecords, Records, RecordsMut},
6 settings::{CellOption, TableOption},
7};
8
9/// A structure to handle special chars.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
11pub struct Charset;
12
13impl Charset {
14 /// Returns [`CleanCharset`] which removes all `\t` and `\r` occurrences.
15 ///
16 /// Notice that tab is just removed rather then being replaced with spaces.
17 /// You might be better call [`TabSize`] first if you not expect such behavior.
18 ///
19 /// # Example
20 ///
21 /// ```
22 /// use tabled::{Table, settings::formatting::Charset};
23 ///
24 /// let text = "Some\ttext\t\twith \\tabs";
25 ///
26 /// let mut table = Table::new([text]);
27 /// table.with(Charset::clean());
28 ///
29 /// assert_eq!(
30 /// table.to_string(),
31 /// "+--------------------+\n\
32 /// | &str |\n\
33 /// +--------------------+\n\
34 /// | Sometextwith \\tabs |\n\
35 /// +--------------------+"
36 /// )
37 /// ```
38 ///
39 /// [`TabSize`]: crate::settings::formatting::TabSize
40 pub fn clean() -> CleanCharset {
41 CleanCharset
42 }
43}
44
45/// [`CleanCharset`] removes all `\t` and `\r` occurrences.
46///
47/// # Example
48///
49/// ```
50/// use std::iter::FromIterator;
51/// use tabled::{
52/// Table, builder::Builder,
53/// settings::formatting::Charset,
54/// };
55///
56/// let text = "Some text which was created on windows \r\n yes they use this \\r\\n";
57///
58/// let mut builder = Builder::from(Table::from_iter([[text]]));
59/// builder.insert_record(0, ["win. text"]);
60///
61/// let mut table = builder.build();
62/// table.with(Charset::clean());
63///
64/// assert_eq!(
65/// table.to_string(),
66/// "+-----------------------------------------+\n\
67/// | win. text |\n\
68/// +-----------------------------------------+\n\
69/// | Some text which was created on windows |\n\
70/// | yes they use this \\r\\n |\n\
71/// +-----------------------------------------+"
72/// )
73/// ```
74#[derive(Debug, Default, Clone)]
75pub struct CleanCharset;
76
77impl CleanCharset {
78 /// Removes all symbols which may break the layout such as `\t`, `\r` and more.
79 ///
80 /// Notice that tab is just removed rather then being replaced with spaces.
81 ///
82 /// # Example
83 ///
84 /// ```
85 /// use tabled::settings::formatting::CleanCharset;
86 ///
87 /// assert_eq!(
88 /// CleanCharset::clean("Some\ttext\t\twith \\tabs\r\nSome"),
89 /// "Sometextwith \\tabs\nSome"
90 /// )
91 /// ```
92 pub fn clean(s: &str) -> Cow<'_, str> {
93 Cow::Owned(clean_charset(s))
94 }
95}
96
97impl<R, D, C> TableOption<R, C, D> for CleanCharset
98where
99 R: Records + ExactRecords + RecordsMut<String> + PeekableRecords,
100{
101 fn change(self, records: &mut R, _: &mut C, _: &mut D) {
102 // TODO: Add a grid iterator which produces POS to squash these for loops
103
104 for row in 0..records.count_rows() {
105 for col in 0..records.count_columns() {
106 let pos = Position::new(row, col);
107 let text = records.get_text(pos);
108 let text = clean_charset(text);
109 records.set(pos, text);
110 }
111 }
112 }
113}
114
115impl<R, C> CellOption<R, C> for CleanCharset
116where
117 R: Records + ExactRecords + PeekableRecords + RecordsMut<String>,
118{
119 fn change(self, records: &mut R, _: &mut C, entity: Entity) {
120 let count_rows = records.count_rows();
121 let count_cols = records.count_columns();
122 for pos in entity.iter(count_rows, count_cols) {
123 let text = records.get_text(pos);
124 let text = clean_charset(text);
125 records.set(pos, text);
126 }
127 }
128}
129
130fn clean_charset(text: &str) -> String {
131 // It's enough for covering '\t' and '\r'
132 // as well as a list of other unwanted escapes.
133 text.replace(|c| c != '\n' && c < ' ', "")
134}