forge_fmt/pp/
convenience.rs1use super::{BeginToken, BreakToken, Breaks, IndentStyle, Printer, SIZE_INFINITY, Token};
2use std::borrow::Cow;
3
4impl Printer {
5 pub fn rbox(&mut self, indent: isize, breaks: Breaks) {
7 self.scan_begin(BeginToken { indent: IndentStyle::Block { offset: indent }, breaks });
8 }
9
10 pub fn ibox(&mut self, indent: isize) {
12 self.rbox(indent, Breaks::Inconsistent);
13 }
14
15 pub fn cbox(&mut self, indent: isize) {
17 self.rbox(indent, Breaks::Consistent);
18 }
19
20 pub fn visual_align(&mut self) {
21 self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent });
22 }
23
24 pub fn break_offset(&mut self, n: usize, off: isize) {
25 self.scan_break(BreakToken { offset: off, blank_space: n, ..BreakToken::default() });
26 }
27
28 pub fn end(&mut self) {
29 self.scan_end();
30 }
31
32 pub fn eof(mut self) -> String {
33 self.scan_eof();
34 self.out
35 }
36
37 pub fn word(&mut self, w: impl Into<Cow<'static, str>>) {
38 self.scan_string(w.into());
39 }
40
41 fn spaces(&mut self, n: usize) {
42 self.break_offset(n, 0);
43 }
44
45 pub fn zerobreak(&mut self) {
46 self.spaces(0);
47 }
48
49 pub fn space(&mut self) {
50 self.spaces(1);
51 }
52
53 pub fn hardbreak(&mut self) {
54 self.spaces(SIZE_INFINITY as usize);
55 }
56
57 pub fn last_token_is_neverbreak(&self) -> bool {
58 if let Some(token) = self.last_token() {
59 return token.is_neverbreak();
60 }
61
62 false
63 }
64
65 pub fn last_token_is_break(&self) -> bool {
66 if let Some(token) = self.last_token() {
67 return matches!(token, Token::Break(_));
68 }
69 false
70 }
71
72 pub fn last_token_is_space(&self) -> bool {
73 if let Some(token) = self.last_token()
74 && token.is_space()
75 {
76 return true;
77 }
78
79 self.out.ends_with(' ')
80 }
81
82 pub fn is_beginning_of_line(&self) -> bool {
83 match self.last_token() {
84 Some(Token::String(s)) => s.ends_with('\n'),
86 Some(last_token) => last_token.is_hardbreak(),
87 None => self.out.is_empty() || self.out.ends_with('\n'),
88 }
89 }
90
91 pub fn is_bol_or_only_ind(&self) -> bool {
97 for i in self.buf.index_range().rev() {
98 let token = &self.buf[i].token;
99 if token.is_hardbreak() {
100 return true;
101 }
102 if let Token::String(s) = token
104 && let Some(pos) = s.rfind('\n')
105 {
106 return s[pos + 1..].trim().is_empty();
107 }
108 if Self::token_has_non_whitespace_content(token) {
109 return false;
110 }
111 }
112
113 let last_line =
114 if let Some(pos) = self.out.rfind('\n') { &self.out[pos + 1..] } else { &self.out[..] };
115
116 last_line.trim().is_empty()
117 }
118
119 fn token_has_non_whitespace_content(token: &Token) -> bool {
120 match token {
121 Token::String(s) => !s.trim().is_empty(),
122 Token::Break(BreakToken { pre_break: Some(s), .. }) => !s.trim().is_empty(),
123 _ => false,
124 }
125 }
126
127 pub(crate) fn hardbreak_tok_offset(offset: isize) -> Token {
128 Token::Break(BreakToken {
129 offset,
130 blank_space: SIZE_INFINITY as usize,
131 ..BreakToken::default()
132 })
133 }
134
135 pub fn hardbreak_if_nonempty(&mut self) {
136 self.scan_break(BreakToken {
137 blank_space: SIZE_INFINITY as usize,
138 if_nonempty: true,
139 ..BreakToken::default()
140 });
141 }
142
143 pub fn neverbreak(&mut self) {
144 self.scan_break(BreakToken { never_break: true, ..BreakToken::default() });
145 }
146}
147
148impl Token {
149 pub(crate) const fn is_neverbreak(&self) -> bool {
150 if let Self::Break(BreakToken { never_break, .. }) = *self {
151 return never_break;
152 }
153 false
154 }
155
156 pub(crate) const fn is_hardbreak(&self) -> bool {
157 if let Self::Break(BreakToken { blank_space, never_break, .. }) = *self {
158 return blank_space == SIZE_INFINITY as usize && !never_break;
159 }
160 false
161 }
162
163 pub(crate) fn is_space(&self) -> bool {
164 match self {
165 Self::Break(BreakToken { offset, blank_space, .. }) => {
166 *offset == 0 && *blank_space == 1
167 }
168 Self::String(s) => s.ends_with(' '),
169 _ => false,
170 }
171 }
172}