1use crate::_private::NonExhaustive;
6use crate::upos_type;
7use format_num_pattern::NumberFormat;
8use rat_event::util::MouseFlags;
9use ratatui::buffer::Buffer;
10use ratatui::layout::Rect;
11use ratatui::prelude::{BlockExt, StatefulWidget, Style};
12use ratatui::text::Line;
13use ratatui::widgets::{Block, Widget};
14
15#[derive(Debug, Default, Clone)]
21pub struct LineNumbers<'a> {
22 start: upos_type,
23 end: Option<upos_type>,
24 cursor: upos_type,
25 relative: bool,
26 flags: Vec<Line<'a>>,
27
28 flag_width: Option<u16>,
29 margin: (u16, u16),
30
31 format: Option<NumberFormat>,
32 style: Style,
33 cursor_style: Option<Style>,
34
35 block: Option<Block<'a>>,
36}
37
38#[derive(Debug, Clone)]
40pub struct LineNumberStyle {
41 pub flag_width: Option<u16>,
42 pub margin: Option<(u16, u16)>,
43 pub format: Option<NumberFormat>,
44 pub style: Style,
45 pub cursor: Option<Style>,
46 pub block: Option<Block<'static>>,
47
48 pub non_exhaustive: NonExhaustive,
49}
50
51#[derive(Debug, Clone)]
53pub struct LineNumberState {
54 pub area: Rect,
55 pub inner: Rect,
56
57 pub start: upos_type,
58
59 pub mouse: MouseFlags,
61
62 pub non_exhaustive: NonExhaustive,
63}
64
65impl<'a> LineNumbers<'a> {
66 pub fn new() -> Self {
67 Self::default()
68 }
69
70 pub fn start(mut self, start: upos_type) -> Self {
72 self.start = start;
73 self
74 }
75
76 pub fn end(mut self, end: upos_type) -> Self {
78 self.end = Some(end);
79 self
80 }
81
82 pub fn cursor(mut self, cursor: upos_type) -> Self {
84 self.cursor = cursor;
85 self
86 }
87
88 pub fn relative(mut self, relative: bool) -> Self {
90 self.relative = relative;
91 self
92 }
93
94 pub fn flags(mut self, flags: Vec<Line<'a>>) -> Self {
96 self.flags = flags;
97 self
98 }
99
100 pub fn flag_width(mut self, width: u16) -> Self {
102 self.flag_width = Some(width);
103 self
104 }
105
106 pub fn margin(mut self, margin: (u16, u16)) -> Self {
108 self.margin = margin;
109 self
110 }
111
112 pub fn format(mut self, format: NumberFormat) -> Self {
114 self.format = Some(format);
115 self
116 }
117
118 pub fn styles(mut self, styles: LineNumberStyle) -> Self {
120 self.style = styles.style;
121 if let Some(flag_width) = styles.flag_width {
122 self.flag_width = Some(flag_width);
123 }
124 if let Some(margin) = styles.margin {
125 self.margin = margin;
126 }
127 if let Some(format) = styles.format {
128 self.format = Some(format);
129 }
130 if let Some(cursor_style) = styles.cursor {
131 self.cursor_style = Some(cursor_style);
132 }
133 if let Some(block) = styles.block {
134 self.block = Some(block);
135 }
136 self.block = self.block.map(|v| v.style(self.style));
137 self
138 }
139
140 pub fn style(mut self, style: Style) -> Self {
142 self.style = style;
143 self.block = self.block.map(|v| v.style(style));
144 self
145 }
146
147 pub fn cursor_style(mut self, style: Style) -> Self {
149 self.cursor_style = Some(style);
150 self
151 }
152
153 pub fn block(mut self, block: Block<'a>) -> Self {
155 self.block = Some(block.style(self.style));
156 self
157 }
158
159 pub fn width(&self) -> u16 {
161 let nr_width = if let Some(end) = self.end {
162 end.ilog10() as u16 + 1
163 } else {
164 (self.start + 100).ilog10() as u16 + 1
165 };
166 let flag_width = if let Some(flag_width) = self.flag_width {
167 flag_width
168 } else {
169 self.flags
170 .iter()
171 .map(|v| v.width() as u16)
172 .max()
173 .unwrap_or_default()
174 };
175 let block_width = {
176 let area = self.block.inner_if_some(Rect::new(0, 0, 2, 2));
177 2 - area.width
178 };
179
180 nr_width + flag_width + self.margin.0 + self.margin.1 + block_width + 1
181 }
182}
183
184impl Default for LineNumberStyle {
185 fn default() -> Self {
186 Self {
187 flag_width: None,
188 margin: None,
189 format: None,
190 style: Default::default(),
191 cursor: None,
192 block: None,
193 non_exhaustive: NonExhaustive,
194 }
195 }
196}
197
198impl StatefulWidget for LineNumbers<'_> {
199 type State = LineNumberState;
200
201 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
202 state.area = area;
203 state.inner = self.block.inner_if_some(area);
204 state.start = self.start;
205 let end = self.end.unwrap_or(upos_type::MAX);
206
207 let nr_width = if let Some(end) = self.end {
208 end.ilog10() as u16 + 1
209 } else {
210 (self.start + 100).ilog10() as u16 + 1
211 };
212
213 let flag_width = if let Some(flag_width) = self.flag_width {
214 flag_width
215 } else {
216 self.flags
217 .iter()
218 .map(|v| v.width() as u16)
219 .max()
220 .unwrap_or_default()
221 };
222
223 let format = if let Some(format) = self.format {
224 format
225 } else {
226 let mut f = "#".repeat(nr_width.saturating_sub(1) as usize);
227 f.push('0');
228 NumberFormat::new(f).expect("valid")
229 };
230
231 let cursor_style = if let Some(cursor_style) = self.cursor_style {
232 cursor_style
233 } else {
234 self.style
235 };
236
237 if let Some(block) = self.block {
238 block.render(area, buf);
239 } else {
240 buf.set_style(area, self.style);
241 }
242
243 let mut tmp = String::new();
244 for y in state.inner.top()..state.inner.bottom() {
245 let (nr, is_cursor) = if self.relative {
246 let pos = self.start + (y - state.inner.y) as upos_type;
247 (pos.abs_diff(self.cursor), pos == self.cursor)
248 } else {
249 let pos = self.start + (y - state.inner.y) as upos_type;
250 (pos, pos == self.cursor)
251 };
252
253 tmp.clear();
254 if nr < end {
255 _ = format.fmt_to(nr, &mut tmp);
256 }
257
258 let style = if is_cursor { cursor_style } else { self.style };
259
260 let nr_area = Rect::new(
261 state.inner.x + self.margin.0, y,
263 nr_width,
264 1,
265 )
266 .intersection(area);
267 buf.set_stringn(nr_area.x, nr_area.y, &tmp, nr_area.width as usize, style);
268
269 if let Some(flags) = self.flags.get((y - state.inner.y) as usize) {
270 flags.render(
271 Rect::new(
272 state.inner.x + self.margin.0 + nr_width + 1,
273 y,
274 flag_width,
275 1,
276 ),
277 buf,
278 );
279 }
280 }
281 }
282}
283
284impl Default for LineNumberState {
285 fn default() -> Self {
286 Self {
287 area: Default::default(),
288 inner: Default::default(),
289 start: 0,
290 mouse: Default::default(),
291 non_exhaustive: NonExhaustive,
292 }
293 }
294}
295
296impl LineNumberState {
297 pub fn new() -> Self {
298 Self::default()
299 }
300}