essential_debugger/
source.rs1use std::fmt::Write;
2
3#[cfg(test)]
4mod tests;
5
6#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct Source {
8 pub other: String,
9 pub predicate: String,
10 pub constraint_line: Option<usize>,
11}
12
13#[derive(Default, Debug, Clone, Copy)]
14pub enum ShowOutput {
15 All,
16 Predicate,
17 #[default]
18 Constraint,
19 ConstraintOnly,
20}
21
22pub fn show_code(source: &Option<Source>, show: ShowOutput) -> String {
23 match source {
24 Some(source) => match show {
25 ShowOutput::All => format!(
26 "{}\n{}",
27 source.other,
28 format_predicate(&source.predicate, &source.constraint_line)
29 ),
30 ShowOutput::Predicate => format_predicate(&source.predicate, &source.constraint_line),
31 ShowOutput::Constraint => format_constraint(&source.predicate, &source.constraint_line),
32 ShowOutput::ConstraintOnly => {
33 constraint_only(&source.predicate, &source.constraint_line)
34 }
35 },
36 None => "No source code available.".to_string(),
37 }
38}
39
40impl Source {
41 pub fn with_predicate(self, predicate: impl Into<String>) -> Self {
42 Source {
43 predicate: predicate.into(),
44 ..self
45 }
46 }
47
48 pub fn with_predicate_find_line(
49 self,
50 predicate: impl Into<String>,
51 constraint_num: usize,
52 ) -> Self {
53 let predicate = predicate.into();
54 let mut count = 0;
55 let constraint_line = predicate.lines().position(|line| {
56 if line.trim().starts_with("constraint ") {
57 let found = count == constraint_num;
58 count += 1;
59 found
60 } else {
61 false
62 }
63 });
64 Source {
65 predicate,
66 constraint_line,
67 ..self
68 }
69 }
70
71 pub fn with_constraint_line_number(self, constraint_line: usize) -> Self {
72 Source {
73 constraint_line: Some(constraint_line),
74 ..self
75 }
76 }
77
78 pub fn with_other_code(self, other: impl Into<String>) -> Self {
79 Source {
80 other: other.into(),
81 ..self
82 }
83 }
84}
85
86fn format_predicate(predicate: &str, constraint_line: &Option<usize>) -> String {
87 match constraint_line {
88 Some(line_num) => predicate.lines().enumerate().fold(
89 String::with_capacity(predicate.len()),
90 |mut s, (i, line)| {
91 if i == *line_num {
92 let _ = writeln!(s, "{}", dialoguer::console::style(line).cyan());
93 } else {
94 let _ = writeln!(s, "{}", line);
95 }
96 s
97 },
98 ),
99 None => predicate.to_string(),
100 }
101}
102
103fn format_constraint(predicate: &str, constraint_line: &Option<usize>) -> String {
104 match constraint_line {
105 Some(line_num) => predicate.lines().enumerate().fold(
106 String::with_capacity(predicate.len()),
107 |mut s, (i, line)| {
108 if i == *line_num {
109 let _ = writeln!(s, "{}", line);
110 } else if line.trim().starts_with("constraint ") {
111 } else {
112 let _ = writeln!(s, "{}", line);
113 }
114 s
115 },
116 ),
117 None => predicate.to_string(),
118 }
119}
120
121fn constraint_only(predicate: &str, constraint_line: &Option<usize>) -> String {
122 match constraint_line {
123 Some(line_num) => match predicate.lines().nth(*line_num) {
124 Some(line) => line.trim().to_string(),
125 None => predicate.to_string(),
126 },
127 None => predicate.to_string(),
128 }
129}
130
131impl From<Option<&str>> for ShowOutput {
132 fn from(value: Option<&str>) -> Self {
133 match value {
134 Some("a") | Some("all") => ShowOutput::All,
135 Some("p") | Some("predicate") => ShowOutput::Predicate,
136 Some("c") | Some("constraint") => ShowOutput::Constraint,
137 Some("co") | Some("constraint only") => ShowOutput::ConstraintOnly,
138 _ => ShowOutput::default(),
139 }
140 }
141}