cursive_logger_view/
view.rs1use cursive_core::{
2 view::{ScrollStrategy, Scrollable, View},
3 views::ScrollView,
4 Printer, Vec2,
5};
6use tap::Pipe;
7use unicode_width::UnicodeWidthStr;
8
9use crate::{
10 log_buffer::{self, GET_LOCK_ERR_MSG},
11 FlexiLoggerView,
12};
13
14impl FlexiLoggerView {
15 pub fn wrap_scroll_view(self) -> ScrollView<Self> {
27 self
28 .scrollable()
29 .scroll_x(true)
30 .scroll_y(true)
31 .scroll_strategy(ScrollStrategy::StickToBottom)
32 }
33
34 pub fn new() -> Self {
36 FlexiLoggerView { indent: true }
37 }
38}
39
40impl View for FlexiLoggerView {
41 fn draw(&self, printer: &Printer<'_, '_>) {
42 let logs = log_buffer::static_logs()
43 .lock()
44 .expect(GET_LOCK_ERR_MSG);
45
46 let skipped = logs
48 .len()
49 .saturating_sub(printer.size.y);
50
51 logs
52 .iter()
53 .skip(skipped)
54 .fold(0, |y, msg| {
55 let log_msg_index = msg.spans_raw().len() - 1;
56
57 let x = msg
58 .spans()
59 .take(log_msg_index)
60 .fold(0, |x, span| {
61 printer.with_style(*span.attr, |p| p.print((x, y), span.content));
62 x + span.width
63 });
64
65 msg
66 .spans()
67 .nth(log_msg_index)
68 .map(|log_msg| {
69 log_msg
70 .content
71 .split('\n')
72 .enumerate()
73 .fold(y, |current_y, (i, part)| {
74 let x_pos = if !self.indent && i > 0 { 0 } else { x };
75 printer
76 .with_style(*log_msg.attr, |p| p.print((x_pos, current_y), part));
77 current_y + 1
78 })
79 })
80 .unwrap_or(y)
81 });
82 }
83
84 fn required_size(&mut self, constraint: Vec2) -> Vec2 {
85 let logs = log_buffer::static_logs()
86 .lock()
87 .expect(GET_LOCK_ERR_MSG);
88
89 let width = logs
91 .iter()
92 .map(|msg| {
93 msg.spans()
94 .map(|x|
95 x.content.split('\n').map(|x| x.width()).max().expect("ERR: required_size(), failed to get width"))
99 .sum::<usize>()
100 })
101 .max()
102 .unwrap_or(1)
103 .pipe(|w|core::cmp::max(w, constraint.x));
104
105 let height = logs
106 .iter()
107 .map(|msg| {
108 msg.spans()
109 .last()
110 .map(|x| x.content.split('\n').count())
111 .expect("ERR: required_size(), the last span message is invalid, and failed to get height.")
112 })
113 .sum::<usize>()
114 .pipe(|h| core::cmp::max(h, constraint.y));
115
116 Vec2::new(width, height)
117 }
118}