Skip to content

Commit 4af6e4c

Browse files
authored
Merge pull request #54 from Canop/backtrace
Use the 't' key to toggle running cargo with backtrace
2 parents 201a767 + 7814691 commit 4af6e4c

File tree

10 files changed

+90
-31
lines changed

10 files changed

+90
-31
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
### next
2+
- propose to toggle backtraces when suggestion is found in cargo's output
3+
14
<a name="v1.1.8"></a>
25
### v1.1.8 - 2021/07/31
36
- move to more recent versions of some crates - Fix #51

Cargo.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "bacon"
3-
version = "1.1.8"
3+
version = "1.1.9-dev"
44
authors = ["dystroy <[email protected]>"]
55
repository = "https://github.com/Canop/bacon"
66
description = "background rust compiler"
@@ -16,14 +16,14 @@ anyhow = "1.0"
1616
cargo_metadata = "0.14"
1717
cli-log = "2.0"
1818
crossbeam = "0.8"
19-
crossterm = "0.20"
19+
crossterm = "0.21"
2020
directories-next = "2.0"
2121
minimad = "0.8"
2222
notify = "5.0.0-pre.11"
2323
lazy-regex = "2.2.1"
2424
log = "0.4"
2525
serde = { version = "1.0", features = ["derive"] }
26-
termimad = "0.14"
26+
termimad = "0.16"
2727
toml = "0.5"
2828
unicode-width = "0.1.8"
2929
vte = "0.8"

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ or
3939

4040
bacon ../broot
4141

42-
### check all targets (tests, examples, etc)
42+
### check all targets (tests, examples, benches, etc)
4343

4444
bacon --job check-all
4545

@@ -129,6 +129,16 @@ Similarly you don't have to stop bacon when you want to use cargo to build the a
129129

130130
Bacon is efficient and doesn't work when there's no notification.
131131

132+
### Can I have all code always checked, including tests, benches and examples ?
133+
134+
You can set the dedicated `check-all` job as as default in the bacon.toml file:
135+
136+
```TOML
137+
default_job = "check-all"
138+
```
139+
140+
Similarly, if your test units are fast enough, you may run them as default, either by editing the default job, by pointing to a new default job, or by creating a new one.
141+
132142
### What are the supported platforms ?
133143

134144
It works on all decent terminals on Linux, Max OSX and Windows.
@@ -151,7 +161,7 @@ A solution is to add this to your init.vim file:
151161

152162
set nowritebackup
153163

154-
This doesn't prevent vim from keeping copies during editions, it just changes the behavior of the write operation.
164+
This doesn't prevent vim from keeping copies during editions, it just changes the behavior of the write operation and has no practical downside.
155165

156166
### Can I get backtraces in tests ?
157167

src/app.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub fn run(w: &mut W, mission: Mission) -> Result<()> {
2424
mission.add_watchs(&mut watcher)?;
2525

2626
let executor = Executor::new(&mission)?;
27-
executor.start()?; // first computation
27+
executor.start(state.new_task())?; // first computation
2828

2929
let event_source = EventSource::new()?;
3030
let user_events = event_source.receiver();
@@ -59,6 +59,16 @@ pub fn run(w: &mut W, mission: Mission) -> Result<()> {
5959
state.toggle_wrap_mode();
6060
state.draw(w)?;
6161
}
62+
(Char('t'), KeyModifiers::NONE) => {
63+
debug!("user toggles backtraces");
64+
state.toggle_backtrace();
65+
if let Err(e) = executor.start(state.new_task()) {
66+
debug!("error sending task: {}", e);
67+
} else {
68+
state.computation_starts();
69+
}
70+
state.draw(w)?;
71+
}
6272
(Home, _) => { state.scroll(w, ScrollCommand::Top)?; }
6373
(End, _) => { state.scroll(w, ScrollCommand::Bottom)?; }
6474
(Up, _) => { state.scroll(w, ScrollCommand::Lines(-1))?; }
@@ -88,7 +98,7 @@ pub fn run(w: &mut W, mission: Mission) -> Result<()> {
8898
}
8999
recv(watch_receiver) -> _ => {
90100
debug!("got a watcher event");
91-
if let Err(e) = executor.start() {
101+
if let Err(e) = executor.start(state.new_task()) {
92102
debug!("error sending task: {}", e);
93103
} else {
94104
state.computation_starts();

src/executor.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,39 @@ use {
1515
/// Channel sizes are designed to avoid useless computations.
1616
pub struct Executor {
1717
pub line_receiver: Receiver<CommandExecInfo>,
18-
task_sender: Sender<()>,
18+
task_sender: Sender<Task>,
1919
stop_sender: Sender<()>, // signal for stopping the thread
2020
thread: thread::JoinHandle<()>,
2121
}
2222

23+
#[derive(Debug, Clone, Copy, PartialEq, Default)]
24+
pub struct Task {
25+
pub backtrace: bool,
26+
}
27+
2328
impl Executor {
2429
/// launch the commands, sends the lines of its stderr on the
2530
/// line channel.
2631
/// If `with_stdout` captures and send also its stdout.
2732
pub fn new(mission: &Mission) -> Result<Self> {
2833
let mut command = mission.get_command();
2934
let with_stdout = mission.need_stdout();
30-
let (task_sender, task_receiver) = bounded(1);
35+
let (task_sender, task_receiver) = bounded::<Task>(1);
3136
let (stop_sender, stop_receiver) = bounded(0);
3237
let (line_sender, line_receiver) = unbounded();
38+
command
39+
.stderr(Stdio::piped())
40+
.stdout(if with_stdout { Stdio::piped() } else { Stdio::null() });
3341
let thread = thread::spawn(move || {
3442
loop {
3543
select! {
36-
recv(task_receiver) -> _ => {
37-
debug!("starting task");
38-
command
39-
.stderr(Stdio::piped())
40-
.stdout(if with_stdout { Stdio::piped() } else { Stdio::null() });
44+
recv(task_receiver) -> task => {
45+
let task = task.unwrap();
46+
debug!("starting task {:?}", task);
47+
command.env(
48+
"RUST_BACKTRACE",
49+
if task.backtrace { "1" } else { "0" },
50+
);
4151
let child = command.spawn();
4252
let mut child = match child {
4353
Ok(child) => child,
@@ -163,8 +173,8 @@ impl Executor {
163173
})
164174
}
165175
/// notify the executor a computation is necessary
166-
pub fn start(&self) -> Result<()> {
167-
self.task_sender.try_send(())?;
176+
pub fn start(&self, task: Task) -> Result<()> {
177+
self.task_sender.try_send(task)?;
168178
Ok(())
169179
}
170180
pub fn die(self) -> Result<()> {

src/line_analysis.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ impl From<&CommandOutputLine> for LineAnalysis {
3030
} else if regex_is_match!("^failures:$", content) {
3131
// this isn't very discriminant...
3232
LineType::Title(Kind::Sum)
33+
} else if regex_is_match!("^note: run with `RUST_BACKTRACE=", content) {
34+
LineType::BacktraceSuggestion
3335
} else {
3436
LineType::Normal
3537
}

src/line_type.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ pub enum LineType {
3030
/// the line saying if a test was passed
3131
TestResult(bool),
3232

33+
/// a suggestion to try with backtrace
34+
BacktraceSuggestion,
35+
3336
/// any other line
3437
Normal,
3538
}

src/report.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use {
1010
pub struct Report {
1111
pub lines: Vec<Line>,
1212
pub stats: Stats,
13+
pub suggest_backtrace: bool,
1314
}
1415

1516
impl Report {
@@ -33,6 +34,7 @@ impl Report {
3334
let mut passed_tests = 0;
3435
let mut cur_err_kind = None; // the current kind among stderr lines
3536
let mut is_in_out_fail = false;
37+
let mut suggest_backtrace = false;
3638
for cmd_line in cmd_lines {
3739
debug!("cmd_line={:?}", &cmd_line);
3840
let line_analysis = LineAnalysis::from(cmd_line);
@@ -95,6 +97,9 @@ impl Report {
9597
cur_err_kind = None;
9698
is_in_out_fail = false;
9799
}
100+
(LineType::BacktraceSuggestion, _) => {
101+
suggest_backtrace = true;
102+
}
98103
_ => {
99104
// TODO add normal if not broken with blank line
100105
warn!("unexpected line: {:#?}", &line);
@@ -133,6 +138,6 @@ impl Report {
133138
// have been read but not added (at start or end)
134139
let mut stats = Stats::from(&lines);
135140
stats.passed_tests = passed_tests;
136-
Ok(Report { lines, stats })
141+
Ok(Report { lines, stats, suggest_backtrace })
137142
}
138143
}

src/state.rs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub struct AppState {
3232
computing: bool,
3333
/// whether the user wants wrapped lines
3434
pub wrap: bool,
35+
/// whether the user wants backtraces
36+
pub backtrace: bool,
3537
/// whether we should display only titles and locations
3638
summary: bool,
3739
reverse: bool,
@@ -62,6 +64,7 @@ impl AppState {
6264
computing: true,
6365
summary: mission.settings.summary,
6466
wrap: mission.settings.wrap,
67+
backtrace: false,
6568
reverse: mission.settings.reverse,
6669
status_skin,
6770
scroll: 0,
@@ -79,6 +82,11 @@ impl AppState {
7982
self.scroll_to_bottom();
8083
}
8184
}
85+
pub fn new_task(&self) -> Task {
86+
Task {
87+
backtrace: self.backtrace,
88+
}
89+
}
8290
pub fn take_lines(&mut self) -> Option<Vec<CommandOutputLine>> {
8391
self.lines.take()
8492
}
@@ -188,6 +196,9 @@ impl AppState {
188196
self.summary ^= true;
189197
self.try_scroll_to_last_top_item();
190198
}
199+
pub fn toggle_backtrace(&mut self) {
200+
self.backtrace ^= true;
201+
}
191202
pub fn toggle_wrap_mode(&mut self) {
192203
self.wrap ^= true;
193204
if self.wrapped_report.is_some() {
@@ -222,20 +233,25 @@ impl AppState {
222233
self.draw(w)
223234
}
224235
fn draw_status(&self, w: &mut W, y: u16) -> Result<()> {
225-
let status = if matches!(self.cmd_result, CommandResult::Report(_)) {
226-
if self.wrap {
227-
"hit *q* to quit, *s* to toggle summary mode, *w* to not wrap lines"
236+
let mut parts = vec!["hit *q* to quit"];
237+
if let CommandResult::Report(report) = &self.cmd_result {
238+
if report.suggest_backtrace {
239+
parts.push("*t* to toggle backtraces");
228240
} else {
229-
"hit *q* to quit, *s* to toggle summary mode, *w* to wrap lines"
241+
parts.push("*s* to toggle summary mode");
242+
if self.wrap {
243+
parts.push("*w* to not wrap lines");
244+
} else {
245+
parts.push("*w* to wrap lines");
246+
}
230247
}
231-
} else {
232-
"hit *q* to quit"
233-
};
248+
}
249+
let status = parts.join(", ");
234250
if self.height > 1 {
235251
goto(w, y)?;
236252
self.status_skin.write_composite_fill(
237253
w,
238-
Composite::from_inline(status),
254+
Composite::from_inline(&status),
239255
self.width.into(),
240256
Alignment::Left,
241257
)?;
@@ -301,7 +317,7 @@ impl AppState {
301317
let width = self.width as usize;
302318
let mut area = Area::new(0, y, self.width, self.page_height() as u16);
303319
let content_height = self.content_height();
304-
let scrollbar = area.scrollbar(self.scroll as i32, content_height as i32);
320+
let scrollbar = area.scrollbar(self.scroll, content_height);
305321
if scrollbar.is_some() {
306322
area.width -= 1;
307323
}

0 commit comments

Comments
 (0)