reedline/painting/
styled_text.rs1use nu_ansi_term::Style;
2
3use crate::Prompt;
4
5use super::utils::strip_ansi;
6
7pub struct StyledText {
9 pub buffer: Vec<(Style, String)>,
11}
12
13impl Default for StyledText {
14 fn default() -> Self {
15 Self::new()
16 }
17}
18
19impl StyledText {
20 pub const fn new() -> Self {
22 Self { buffer: vec![] }
23 }
24
25 pub fn push(&mut self, styled_string: (Style, String)) {
27 self.buffer.push(styled_string);
28 }
29
30 pub fn render_around_insertion_point(
38 &self,
39 insertion_point: usize,
40 prompt: &dyn Prompt,
41 use_ansi_coloring: bool,
43 ) -> (String, String) {
44 let mut current_idx = 0;
45 let mut left_string = String::new();
46 let mut right_string = String::new();
47
48 let multiline_prompt = prompt.render_prompt_multiline_indicator();
49 let prompt_style = Style::new().fg(prompt.get_prompt_multiline_color());
50
51 for pair in &self.buffer {
52 if current_idx >= insertion_point {
53 right_string.push_str(&render_as_string(pair, &prompt_style, &multiline_prompt));
54 } else if pair.1.len() + current_idx <= insertion_point {
55 left_string.push_str(&render_as_string(pair, &prompt_style, &multiline_prompt));
56 } else if pair.1.len() + current_idx > insertion_point {
57 let offset = insertion_point - current_idx;
58
59 let left_side = pair.1[..offset].to_string();
60 let right_side = pair.1[offset..].to_string();
61
62 left_string.push_str(&render_as_string(
63 &(pair.0, left_side),
64 &prompt_style,
65 &multiline_prompt,
66 ));
67 right_string.push_str(&render_as_string(
68 &(pair.0, right_side),
69 &prompt_style,
70 &multiline_prompt,
71 ));
72 }
73 current_idx += pair.1.len();
74 }
75
76 if use_ansi_coloring {
77 (left_string, right_string)
78 } else {
79 (strip_ansi(&left_string), strip_ansi(&right_string))
80 }
81 }
82
83 pub fn render_simple(&self) -> String {
85 self.buffer
86 .iter()
87 .map(|(style, text)| style.paint(text).to_string())
88 .collect()
89 }
90
91 pub fn raw_string(&self) -> String {
93 self.buffer.iter().map(|(_, str)| str.as_str()).collect()
94 }
95}
96
97fn render_as_string(
98 renderable: &(Style, String),
99 prompt_style: &Style,
100 multiline_prompt: &str,
101) -> String {
102 let mut rendered = String::new();
103 let formatted_multiline_prompt = format!("\n{multiline_prompt}");
104 for (line_number, line) in renderable.1.split('\n').enumerate() {
105 if line_number != 0 {
106 rendered.push_str(&prompt_style.paint(&formatted_multiline_prompt).to_string());
107 }
108 rendered.push_str(&renderable.0.paint(line).to_string());
109 }
110 rendered
111}