-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathlayout.rs
197 lines (188 loc) · 8.89 KB
/
layout.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/// Creates a single constraint.
///
/// If creating an array of constraints, you probably want to use
/// [`constraints!`] instead.
///
/// # Examples
///
/// ```
/// # use ratatui_core::layout::Constraint;
/// use ratatui_macros::constraint;
/// assert_eq!(constraint!(>= 3 + 4), Constraint::Min(7));
/// assert_eq!(constraint!(<= 3 + 4), Constraint::Max(7));
/// assert_eq!(constraint!(== 1 / 3), Constraint::Ratio(1, 3));
/// assert_eq!(constraint!(== 3), Constraint::Length(3));
/// assert_eq!(constraint!(== 10 %), Constraint::Percentage(10));
/// assert_eq!(constraint!(*= 1), Constraint::Fill(1));
/// ```
#[macro_export]
macro_rules! constraint {
(== $token:tt %) => {
$crate::ratatui_core::layout::Constraint::Percentage($token)
};
(>= $expr:expr) => {
$crate::ratatui_core::layout::Constraint::Min($expr)
};
(<= $expr:expr) => {
$crate::ratatui_core::layout::Constraint::Max($expr)
};
(== $num:tt / $denom:tt) => {
$crate::ratatui_core::layout::Constraint::Ratio($num as u32, $denom as u32)
};
(== $expr:expr) => {
$crate::ratatui_core::layout::Constraint::Length($expr)
};
(*= $expr:expr) => {
$crate::ratatui_core::layout::Constraint::Fill($expr)
};
}
/// Creates an array of constraints.
///
/// See [`constraint!`] for more information.
///
/// If you want to solve the constraints, see
/// [`vertical!`] and [`horizontal!`] macros.
///
/// # Examples
///
/// ```rust
/// use ratatui_macros::constraints;
/// assert_eq!(constraints![==5, ==30%, >=3, <=1, ==1/2].len(), 5);
/// assert_eq!(constraints![==5; 5].len(), 5);
/// ```
///
/// ```rust
/// # use ratatui_core::layout::Constraint;
/// # use ratatui_macros::constraints;
/// assert_eq!(
/// constraints![==50, ==30%, >=3, <=1, ==1/2, *=1],
/// [
/// Constraint::Length(50),
/// Constraint::Percentage(30),
/// Constraint::Min(3),
/// Constraint::Max(1),
/// Constraint::Ratio(1, 2),
/// Constraint::Fill(1),
/// ]
/// )
/// ```
#[macro_export]
macro_rules! constraints {
// Note: this implementation forgoes speed for the sake of simplicity. Adding variations of the
// comma and semicolon rules for each constraint type would be faster, but would result in a lot
// of duplicated code.
// Cannot start the constraints macro with a ,
([ , $($rest:tt)* ] -> () []) => {
compile_error!("No rules expected the token `,` while trying to match the end of the macro")
};
// Comma finishes a constraint element, so parse it and continue.
// When a comma is encountered, it marks the end of a constraint element, so this rule is responsible
// for parsing the constraint expression up to the comma and continuing the parsing process.
// It accumulated the $partial contains a Constraint and is parsed using a separate $crate::constraint! macro.
// The constraint is then appended to the list of parsed constraints.
//
// [ , $($rest:tt)* ] -> In the rule matcher, this pattern matches a comma followed
// by the rest of the tokens. The comma signals the end of
// the current constraint element.
// ($($partial:tt)*) -> In the rule matcher, this contains the partial tokens
// accumulated so far for the current constraint element.
// [$($parsed:tt)* ] -> This contains the constraints that have been successfully
// parsed so far.
// $crate::constraint!($($partial)*) -> This macro call parses and expands the accumulated
// partial tokens into a single Constraint expression.
// [$($parsed)* $crate::constraint!(...)] -> Appends the newly parsed constraint to the list of
// already parsed constraints.
([ , $($rest:tt)* ] -> ($($partial:tt)*) [ $($parsed:tt)* ]) => {
$crate::constraints!([$($rest)*] -> () [$($parsed)* $crate::constraint!($($partial)*) ,])
};
// Semicolon indicates that there's repetition. The trailing comma is required because the 'entrypoint'
// rule adds a trailing comma.
// This rule is triggered when a semicolon is encountered, indicating that there is repetition of
// constraints. It handles the repetition logic by parsing the count and generating an array of
// constraints using the $crate::constraint! macro.
//
// [ ; $count:expr , ] -> In the rule matcher, this pattern matches a semicolon
// followed by an expression representing the count, and a
// trailing comma.
// ($($partial:tt)*) -> In the rule matcher, this contains the partial tokens
// accumulated so far for the current constraint element.
// This represents everything before the ;
// [] -> There will be no existed parsed constraints when using ;
// $crate::constraint!($($partial)*) -> This macro call parses and expands the accumulated
// partial tokens into a single Constraint expression.
// [$crate::constraint!(...) ; $count] -> Generates an array of constraints by repeating the
// parsed constraint count number of times.
([ ; $count:expr , ] -> ($($partial:tt)*) []) => {
[$crate::constraint!($($partial)*); $count]
};
// Pull the first token (which can't be a comma or semicolon) onto the accumulator.
// if first token is a comma or semicolon, previous rules will match before this rule
//
// [ $head:tt $($rest:tt)* ] -> In the rule matcher, this pulls a single `head` token
// out of the previous rest, and puts
// the remaining into `rest`
// [ $($rest)* ] -> This is what is fed back into the `constraints!` macro
// as the first segment for the match rule
//
// ($($partial:tt)*) -> In the rule matcher, this contains previous partial
// tokens that will make up a `Constraint` expression
// ($($partial)* $head) -> This combines head with the previous partial tokens
// i.e. this is the accumulated tokens
//
// [ $($parsed:tt)* ] -> In the rule matcher, this contains all parsed exprs
// [$($parsed)* ] -> These are passed on to the next match untouched.
([ $head:tt $($rest:tt)* ] -> ($($partial:tt)*) [ $($parsed:tt)* ]) => {
$crate::constraints!([$($rest)*] -> ($($partial)* $head) [$($parsed)* ])
};
// This rule is triggered when there are no more input tokens to process. It signals the end of the
// macro invocation and outputs the parsed constraints as a final array.
([$(,)?] -> () [ $( $parsed:tt )* ]) => {
[$($parsed)*]
};
// Entrypoint where there's no comma at the end.
// We add a comma to make sure there's always a trailing comma.
// Right-hand side will accumulate the actual `Constraint` literals.
($( $constraint:tt )+) => {
$crate::constraints!([ $($constraint)+ , ] -> () [])
};
}
/// Creates a vertical layout with specified constraints.
///
/// It accepts a series of constraints and applies them to create a vertical layout. The constraints
/// can include fixed sizes, minimum and maximum sizes, percentages, and ratios.
///
/// See [`constraint!`] or [`constraints!`] for more information.
///
/// # Examples
///
/// ```
/// // Vertical layout with a fixed size and a percentage constraint
/// use ratatui_macros::vertical;
/// vertical![== 50, == 30%];
/// ```
#[macro_export]
macro_rules! vertical {
($( $constraint:tt )+) => {
$crate::ratatui_core::layout::Layout::vertical($crate::constraints!( $($constraint)+ ))
};
}
/// Creates a horizontal layout with specified constraints.
///
/// It takes a series of constraints and applies them to create a horizontal layout. The constraints
/// can include fixed sizes, minimum and maximum sizes, percentages, and ratios.
///
/// See [`constraint!`] or [`constraints!`] for more information.
///
/// # Examples
///
/// ```
/// // Horizontal layout with a ratio constraint and a minimum size constraint
/// use ratatui_macros::horizontal;
/// horizontal![== 1/3, >= 100];
/// ```
#[macro_export]
macro_rules! horizontal {
($( $constraint:tt )+) => {
$crate::ratatui_core::layout::Layout::horizontal($crate::constraints!( $($constraint)+ ))
};
}