Skip to content

Commit 3aeb96b

Browse files
feat!: Add "back-or-quit" and don't quit on "back"
The new default "back" action no longer quits, and there is a new "back-or-quit" which restores the old behavior. This also by nature makes the same change for job refs: "previous" no longer quits automatically but "previous-or-quit" does.
1 parent ceed1fa commit 3aeb96b

File tree

6 files changed

+49
-19
lines changed

6 files changed

+49
-19
lines changed

src/conf/action.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ fn test_action_string_round_trip() {
142142
let actions = vec![
143143
Action::Job(JobRef::Default),
144144
Action::Job(JobRef::Initial),
145+
Action::Job(JobRef::PreviousOrQuit),
145146
Action::Job(JobRef::Previous),
146147
Action::Job(JobRef::Concrete(ConcreteJobRef {
147148
name_or_alias: NameOrAlias::Name("run".to_string()),

src/internal.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ use {
2222
/// to a key or ran after a successful job
2323
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2424
pub enum Internal {
25-
Back, // leave help, clear search, go to previous job, leave, etc.
25+
Back, // leave help, clear search, go to previous job, leave, etc.
26+
BackOrQuit, // same as Back but quits if there is nothing to go back to
2627
CopyUnstyledOutput,
2728
FocusSearch,
2829
FocusGoto,
@@ -52,6 +53,9 @@ impl Internal {
5253
pub fn doc(&self) -> String {
5354
match self {
5455
Self::Back => "back to previous page or job".to_string(),
56+
Self::BackOrQuit => {
57+
"back to previous page or job, quitting if there is none".to_string()
58+
}
5559
Self::CopyUnstyledOutput => "copy current job's output".to_string(),
5660
Self::FocusSearch => "focus search".to_string(),
5761
Self::FocusGoto => "focus goto".to_string(),
@@ -85,6 +89,7 @@ impl fmt::Display for Internal {
8589
) -> fmt::Result {
8690
match self {
8791
Self::Back => write!(f, "back"),
92+
Self::BackOrQuit => write!(f, "back-or-quit"),
8893
Self::CopyUnstyledOutput => write!(f, "copy-unstyled-output"),
8994
Self::Help => write!(f, "help"),
9095
Self::NoOp => write!(f, "no-op"),
@@ -124,6 +129,7 @@ impl std::str::FromStr for Internal {
124129
}
125130
match s {
126131
"back" => Ok(Self::Back),
132+
"back-or-quit" => Ok(Self::BackOrQuit),
127133
"help" => Ok(Self::Help),
128134
"quit" => Ok(Self::Quit),
129135
"refresh" => Ok(Self::Refresh),
@@ -200,6 +206,7 @@ fn test_internal_string_round_trip() {
200206
use crate::Volume;
201207
let internals = [
202208
Internal::Back,
209+
Internal::BackOrQuit,
203210
Internal::FocusSearch,
204211
Internal::Help,
205212
Internal::NoOp,

src/jobs/job_ref.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub enum JobRef {
99
Default,
1010
Initial,
1111
Previous,
12+
PreviousOrQuit,
1213
Concrete(ConcreteJobRef),
1314
Scope(Scope),
1415
}
@@ -46,6 +47,7 @@ impl fmt::Display for JobRef {
4647
Self::Default => write!(f, "default"),
4748
Self::Initial => write!(f, "initial"),
4849
Self::Previous => write!(f, "previous"),
50+
Self::PreviousOrQuit => write!(f, "previous-or-quit"),
4951
Self::Scope(Scope { tests }) => write!(f, "scope:{}", tests.join(",")),
5052
Self::Concrete(concrete) => write!(f, "{}", concrete),
5153
}
@@ -58,6 +60,7 @@ impl From<&str> for JobRef {
5860
"^default$"i => Self::Default,
5961
"^initial$"i => Self::Initial,
6062
"^previous$"i => Self::Previous,
63+
"^previous-or-quit$"i => Self::PreviousOrQuit,
6164
"^scope:(?<tests>.+)$"i => Self::Scope(Scope {
6265
tests: tests
6366
.split(',')
@@ -76,6 +79,7 @@ fn test_job_ref_string_round_trip() {
7679
JobRef::Default,
7780
JobRef::Initial,
7881
JobRef::Previous,
82+
JobRef::PreviousOrQuit,
7983
JobRef::Concrete(ConcreteJobRef {
8084
name_or_alias: NameOrAlias::Name("run".to_string()),
8185
scope: Scope::default(),

src/jobs/job_stack.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
use {
22
crate::*,
3-
anyhow::{
4-
Result,
5-
anyhow,
6-
},
3+
anyhow::anyhow,
74
};
85

96
/// The stack of jobs that bacon ran, allowing to get back to the previous one,
@@ -13,15 +10,21 @@ pub struct JobStack {
1310
entries: Vec<ConcreteJobRef>,
1411
}
1512

13+
/// Possible variants:
14+
/// `Ok(job)` -> application should run the given job
15+
/// `Err(None)` -> application should exit
16+
/// `Err(Some(err))` -> application should exit with error
17+
pub type JobResult = Result<(ConcreteJobRef, Job), Option<anyhow::Error>>;
18+
1619
impl JobStack {
1720
/// Apply the job ref instruction to determine the job to run, updating the stack.
1821
///
19-
/// When no job is returned, the application is supposed to quit.
22+
/// See [`JobResult`] for meanings of return values.
2023
pub fn pick_job(
2124
&mut self,
2225
job_ref: &JobRef,
2326
settings: &Settings,
24-
) -> Result<Option<(ConcreteJobRef, Job)>> {
27+
) -> JobResult {
2528
debug!("picking job {job_ref:?}");
2629
let concrete = match job_ref {
2730
JobRef::Default => settings.default_job.clone(),
@@ -30,7 +33,7 @@ impl JobStack {
3033
.as_ref()
3134
.unwrap_or(&settings.default_job)
3235
.clone(),
33-
JobRef::Previous => {
36+
JobRef::PreviousOrQuit | JobRef::Previous => {
3437
let current = self.entries.pop();
3538
match self.entries.pop() {
3639
Some(concrete) => concrete,
@@ -45,7 +48,16 @@ impl JobStack {
4548
}
4649
}
4750
None => {
48-
return Ok(None);
51+
if let JobRef::PreviousOrQuit = job_ref {
52+
return Err(None);
53+
}
54+
55+
// this has a side effect of reloading the job, which isn't ideal
56+
// but the main loop needs some mission to avoid spinning forever
57+
ConcreteJobRef {
58+
name_or_alias: current.unwrap().name_or_alias,
59+
scope: Scope::default(),
60+
}
4961
}
5062
}
5163
}
@@ -56,7 +68,7 @@ impl JobStack {
5668
scope: scope.clone(),
5769
},
5870
None => {
59-
return Ok(None);
71+
return Err(None);
6072
}
6173
},
6274
};
@@ -71,6 +83,6 @@ impl JobStack {
7183
if self.entries.last() != Some(&concrete) {
7284
self.entries.push(concrete.clone());
7385
}
74-
Ok(Some((concrete, job)))
86+
Ok((concrete, job))
7587
}
7688
}

src/tui/app.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,10 @@ pub fn run(
6363
let mut next_job = JobRef::Initial;
6464
let mut message = None;
6565
loop {
66-
let (concrete_job_ref, job) = match job_stack.pick_job(&next_job, &settings)? {
67-
Some(t) => t,
68-
None => {
69-
break;
70-
}
66+
let (concrete_job_ref, job) = match job_stack.pick_job(&next_job, &settings) {
67+
Ok(t) => t,
68+
Err(None) => break,
69+
Err(Some(err)) => return Err(err),
7170
};
7271
let mission = location.mission(concrete_job_ref, &job, &settings)?;
7372
let do_after =
@@ -270,9 +269,14 @@ fn run_mission(
270269
.push(Message::short(format!("Export *{}* done", &export_name)));
271270
}
272271
Action::Internal(internal) => match internal {
273-
Internal::Back => {
272+
Internal::BackOrQuit | Internal::Back => {
274273
if !state.back() {
275-
mission_end = Some(DoAfterMission::NextJob(JobRef::Previous));
274+
let job_ref = if let Internal::Back = internal {
275+
JobRef::Previous
276+
} else {
277+
JobRef::PreviousOrQuit
278+
};
279+
mission_end = Some(DoAfterMission::NextJob(job_ref));
276280
}
277281
}
278282
Internal::CopyUnstyledOutput => {

website/docs/config.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ An export action is defined as `export:` followed by the export name.
172172
internal | default binding | meaning
173173
:-|:-|:-
174174
back | <kbd>Esc</kbd> | get back to the previous page or job, or cancel search
175+
back-or-quit | | back to previous page or job, quitting if there is none
175176
copy-unstyled-output | | write the currently displayed job output to the clipboard
176177
focus-search | <kbd>/</kbd> | focus the search input
177178
help | <kbd>h</kbd> or <kbd>?</kbd> | open the help page
@@ -222,7 +223,8 @@ job reference | meaning
222223
-|-
223224
`job:default` | the job defined as *default* in the bacon.toml file
224225
`job:initial` | the job specified as argument, or the default one if there was none explicit
225-
`job:previous` | the job which ran before, if any (or we would quit). The `back` internal has usually the same effect
226+
`job:previous` | the job which ran before, if any. The `back` internal has usually the same effect
227+
`job:previous-or-quit` | same as `job:previous`, but will quit if there was no job. The `back-or-quit` internal has usually the same effect
226228

227229
# Exports
228230

0 commit comments

Comments
 (0)